mirror of
https://github.com/google/blockly.git
synced 2025-12-15 13:50:08 +01:00
chore: delete blockfactory_old (#7933)
This commit is contained in:
@@ -1,794 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2012 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Blocks for Blockly's Block Factory application.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
Blockly.Blocks['factory_base'] = {
|
||||
// Base of new block.
|
||||
init: function() {
|
||||
this.setColour(120);
|
||||
this.appendDummyInput()
|
||||
.appendField('name')
|
||||
.appendField(new Blockly.FieldTextInput('block_type'), 'NAME');
|
||||
this.appendStatementInput('INPUTS')
|
||||
.setCheck('Input')
|
||||
.appendField('inputs');
|
||||
var dropdown = new Blockly.FieldDropdown([
|
||||
['automatic inputs', 'AUTO'],
|
||||
['external inputs', 'EXT'],
|
||||
['inline inputs', 'INT']]);
|
||||
this.appendDummyInput()
|
||||
.appendField(dropdown, 'INLINE');
|
||||
dropdown = new Blockly.FieldDropdown([
|
||||
['no connections', 'NONE'],
|
||||
['← left output', 'LEFT'],
|
||||
['↕ top+bottom connections', 'BOTH'],
|
||||
['↑ top connection', 'TOP'],
|
||||
['↓ bottom connection', 'BOTTOM']],
|
||||
function(option) {
|
||||
this.sourceBlock_.updateShape_(option);
|
||||
// Connect a shadow block to this new input.
|
||||
this.sourceBlock_.spawnOutputShadow_(option);
|
||||
});
|
||||
this.appendDummyInput()
|
||||
.appendField(dropdown, 'CONNECTIONS');
|
||||
this.appendValueInput('COLOUR')
|
||||
.setCheck('Colour')
|
||||
.appendField('colour');
|
||||
this.setTooltip('Build a custom block by plugging\n' +
|
||||
'fields, inputs and other blocks here.');
|
||||
this.setHelpUrl(
|
||||
'https://developers.google.com/blockly/guides/create-custom-blocks/block-factory');
|
||||
},
|
||||
mutationToDom: function() {
|
||||
var container = Blockly.utils.xml.createElement('mutation');
|
||||
container.setAttribute('connections', this.getFieldValue('CONNECTIONS'));
|
||||
return container;
|
||||
},
|
||||
domToMutation: function(xmlElement) {
|
||||
var connections = xmlElement.getAttribute('connections');
|
||||
this.updateShape_(connections);
|
||||
},
|
||||
spawnOutputShadow_: function(option) {
|
||||
// Helper method for deciding which type of outputs this block needs
|
||||
// to attach shadow blocks to.
|
||||
switch (option) {
|
||||
case 'LEFT':
|
||||
this.connectOutputShadow_('OUTPUTTYPE');
|
||||
break;
|
||||
case 'TOP':
|
||||
this.connectOutputShadow_('TOPTYPE');
|
||||
break;
|
||||
case 'BOTTOM':
|
||||
this.connectOutputShadow_('BOTTOMTYPE');
|
||||
break;
|
||||
case 'BOTH':
|
||||
this.connectOutputShadow_('TOPTYPE');
|
||||
this.connectOutputShadow_('BOTTOMTYPE');
|
||||
break;
|
||||
}
|
||||
},
|
||||
connectOutputShadow_: function(outputType) {
|
||||
// Helper method to create & connect shadow block.
|
||||
var type = this.workspace.newBlock('type_null');
|
||||
type.setShadow(true);
|
||||
type.outputConnection.connect(this.getInput(outputType).connection);
|
||||
type.initSvg();
|
||||
type.render();
|
||||
},
|
||||
updateShape_: function(option) {
|
||||
var outputExists = this.getInput('OUTPUTTYPE');
|
||||
var topExists = this.getInput('TOPTYPE');
|
||||
var bottomExists = this.getInput('BOTTOMTYPE');
|
||||
if (option === 'LEFT') {
|
||||
if (!outputExists) {
|
||||
this.addTypeInput_('OUTPUTTYPE', 'output type');
|
||||
}
|
||||
} else if (outputExists) {
|
||||
this.removeInput('OUTPUTTYPE');
|
||||
}
|
||||
if (option === 'TOP' || option === 'BOTH') {
|
||||
if (!topExists) {
|
||||
this.addTypeInput_('TOPTYPE', 'top type');
|
||||
}
|
||||
} else if (topExists) {
|
||||
this.removeInput('TOPTYPE');
|
||||
}
|
||||
if (option === 'BOTTOM' || option === 'BOTH') {
|
||||
if (!bottomExists) {
|
||||
this.addTypeInput_('BOTTOMTYPE', 'bottom type');
|
||||
}
|
||||
} else if (bottomExists) {
|
||||
this.removeInput('BOTTOMTYPE');
|
||||
}
|
||||
},
|
||||
addTypeInput_: function(name, label) {
|
||||
this.appendValueInput(name)
|
||||
.setCheck('Type')
|
||||
.appendField(label);
|
||||
this.moveInputBefore(name, 'COLOUR');
|
||||
}
|
||||
};
|
||||
|
||||
var FIELD_MESSAGE = 'fields %1 %2';
|
||||
var FIELD_ARGS = [
|
||||
{
|
||||
"type": "field_dropdown",
|
||||
"name": "ALIGN",
|
||||
"options": [['left', 'LEFT'], ['right', 'RIGHT'], ['centre', 'CENTRE']],
|
||||
},
|
||||
{
|
||||
"type": "input_statement",
|
||||
"name": "FIELDS",
|
||||
"check": "Field"
|
||||
}
|
||||
];
|
||||
|
||||
var TYPE_MESSAGE = 'type %1';
|
||||
var TYPE_ARGS = [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "TYPE",
|
||||
"check": "Type",
|
||||
"align": "RIGHT"
|
||||
}
|
||||
];
|
||||
|
||||
Blockly.Blocks['input_value'] = {
|
||||
// Value input.
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": "value input %1 %2",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_input",
|
||||
"name": "INPUTNAME",
|
||||
"text": "NAME"
|
||||
},
|
||||
{
|
||||
"type": "input_dummy"
|
||||
}
|
||||
],
|
||||
"message1": FIELD_MESSAGE,
|
||||
"args1": FIELD_ARGS,
|
||||
"message2": TYPE_MESSAGE,
|
||||
"args2": TYPE_ARGS,
|
||||
"previousStatement": "Input",
|
||||
"nextStatement": "Input",
|
||||
"colour": 210,
|
||||
"tooltip": "A value socket for horizontal connections.",
|
||||
"helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=71"
|
||||
});
|
||||
},
|
||||
onchange: function() {
|
||||
inputNameCheck(this);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['input_statement'] = {
|
||||
// Statement input.
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": "statement input %1 %2",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_input",
|
||||
"name": "INPUTNAME",
|
||||
"text": "NAME"
|
||||
},
|
||||
{
|
||||
"type": "input_dummy"
|
||||
},
|
||||
],
|
||||
"message1": FIELD_MESSAGE,
|
||||
"args1": FIELD_ARGS,
|
||||
"message2": TYPE_MESSAGE,
|
||||
"args2": TYPE_ARGS,
|
||||
"previousStatement": "Input",
|
||||
"nextStatement": "Input",
|
||||
"colour": 210,
|
||||
"tooltip": "A statement socket for enclosed vertical stacks.",
|
||||
"helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=246"
|
||||
});
|
||||
},
|
||||
onchange: function() {
|
||||
inputNameCheck(this);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['input_dummy'] = {
|
||||
// Dummy input.
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": "dummy input",
|
||||
"message1": FIELD_MESSAGE,
|
||||
"args1": FIELD_ARGS,
|
||||
"previousStatement": "Input",
|
||||
"nextStatement": "Input",
|
||||
"colour": 210,
|
||||
"tooltip": "For adding fields on a separate row with no " +
|
||||
"connections. Alignment options (left, right, centre) " +
|
||||
"apply only to multi-line fields.",
|
||||
"helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=293"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['field_static'] = {
|
||||
// Text value.
|
||||
init: function() {
|
||||
this.setColour(160);
|
||||
this.appendDummyInput()
|
||||
.appendField('text')
|
||||
.appendField(new Blockly.FieldTextInput(''), 'TEXT');
|
||||
this.setPreviousStatement(true, 'Field');
|
||||
this.setNextStatement(true, 'Field');
|
||||
this.setTooltip('Static text that serves as a label.');
|
||||
this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=88');
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['field_input'] = {
|
||||
// Text input.
|
||||
init: function() {
|
||||
this.setColour(160);
|
||||
this.appendDummyInput()
|
||||
.appendField('text input')
|
||||
.appendField(new Blockly.FieldTextInput('default'), 'TEXT')
|
||||
.appendField(',')
|
||||
.appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME');
|
||||
this.setPreviousStatement(true, 'Field');
|
||||
this.setNextStatement(true, 'Field');
|
||||
this.setTooltip('An input field for the user to enter text.');
|
||||
this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=319');
|
||||
},
|
||||
onchange: function() {
|
||||
fieldNameCheck(this);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['field_number'] = {
|
||||
// Numeric input.
|
||||
init: function() {
|
||||
this.setColour(160);
|
||||
this.appendDummyInput()
|
||||
.appendField('numeric input')
|
||||
.appendField(new Blockly.FieldNumber(0), 'VALUE')
|
||||
.appendField(',')
|
||||
.appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME');
|
||||
this.appendDummyInput()
|
||||
.appendField('min')
|
||||
.appendField(new Blockly.FieldNumber(-Infinity), 'MIN')
|
||||
.appendField('max')
|
||||
.appendField(new Blockly.FieldNumber(Infinity), 'MAX')
|
||||
.appendField('precision')
|
||||
.appendField(new Blockly.FieldNumber(0, 0), 'PRECISION');
|
||||
this.setPreviousStatement(true, 'Field');
|
||||
this.setNextStatement(true, 'Field');
|
||||
this.setTooltip('An input field for the user to enter a number.');
|
||||
this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=319');
|
||||
},
|
||||
onchange: function() {
|
||||
fieldNameCheck(this);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['field_angle'] = {
|
||||
// Angle input.
|
||||
init: function() {
|
||||
this.setColour(160);
|
||||
this.appendDummyInput()
|
||||
.appendField('angle input')
|
||||
.appendField(new Blockly.FieldAngle('90'), 'ANGLE')
|
||||
.appendField(',')
|
||||
.appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME');
|
||||
this.setPreviousStatement(true, 'Field');
|
||||
this.setNextStatement(true, 'Field');
|
||||
this.setTooltip('An input field for the user to enter an angle.');
|
||||
this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=372');
|
||||
},
|
||||
onchange: function() {
|
||||
fieldNameCheck(this);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['field_dropdown'] = {
|
||||
// Dropdown menu.
|
||||
init: function() {
|
||||
this.appendDummyInput()
|
||||
.appendField('dropdown')
|
||||
.appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME');
|
||||
this.optionCount_ = 3;
|
||||
this.updateShape_();
|
||||
this.setPreviousStatement(true, 'Field');
|
||||
this.setNextStatement(true, 'Field');
|
||||
this.setMutator(new Blockly.icons.MutatorIcon(['field_dropdown_option']));
|
||||
this.setColour(160);
|
||||
this.setTooltip('Dropdown menu with a list of options.');
|
||||
this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=386');
|
||||
},
|
||||
mutationToDom: function(workspace) {
|
||||
// Create XML to represent menu options.
|
||||
var container = Blockly.utils.xml.createElement('mutation');
|
||||
container.setAttribute('options', this.optionCount_);
|
||||
return container;
|
||||
},
|
||||
domToMutation: function(container) {
|
||||
// Parse XML to restore the menu options.
|
||||
this.optionCount_ = parseInt(container.getAttribute('options'), 10);
|
||||
this.updateShape_();
|
||||
},
|
||||
decompose: function(workspace) {
|
||||
// Populate the mutator's dialog with this block's components.
|
||||
var containerBlock = workspace.newBlock('field_dropdown_container');
|
||||
containerBlock.initSvg();
|
||||
var connection = containerBlock.getInput('STACK').connection;
|
||||
for (var i = 0; i < this.optionCount_; i++) {
|
||||
var optionBlock = workspace.newBlock('field_dropdown_option');
|
||||
optionBlock.initSvg();
|
||||
connection.connect(optionBlock.previousConnection);
|
||||
connection = optionBlock.nextConnection;
|
||||
}
|
||||
return containerBlock;
|
||||
},
|
||||
compose: function(containerBlock) {
|
||||
// Reconfigure this block based on the mutator dialog's components.
|
||||
var optionBlock = containerBlock.getInputTargetBlock('STACK');
|
||||
// Count number of inputs.
|
||||
var data = [];
|
||||
while (optionBlock) {
|
||||
data.push([optionBlock.userData_, optionBlock.cpuData_]);
|
||||
optionBlock = optionBlock.nextConnection &&
|
||||
optionBlock.nextConnection.targetBlock();
|
||||
}
|
||||
this.optionCount_ = data.length;
|
||||
this.updateShape_();
|
||||
// Restore any data.
|
||||
for (var i = 0; i < this.optionCount_; i++) {
|
||||
this.setFieldValue(data[i][0] || 'option', 'USER' + i);
|
||||
this.setFieldValue(data[i][1] || 'OPTIONNAME', 'CPU' + i);
|
||||
}
|
||||
},
|
||||
saveConnections: function(containerBlock) {
|
||||
// Store names and values for each option.
|
||||
var optionBlock = containerBlock.getInputTargetBlock('STACK');
|
||||
var i = 0;
|
||||
while (optionBlock) {
|
||||
optionBlock.userData_ = this.getFieldValue('USER' + i);
|
||||
optionBlock.cpuData_ = this.getFieldValue('CPU' + i);
|
||||
i++;
|
||||
optionBlock = optionBlock.nextConnection &&
|
||||
optionBlock.nextConnection.targetBlock();
|
||||
}
|
||||
},
|
||||
updateShape_: function() {
|
||||
// Modify this block to have the correct number of options.
|
||||
// Add new options.
|
||||
for (var i = 0; i < this.optionCount_; i++) {
|
||||
if (!this.getInput('OPTION' + i)) {
|
||||
this.appendDummyInput('OPTION' + i)
|
||||
.appendField(new Blockly.FieldTextInput('option'), 'USER' + i)
|
||||
.appendField(',')
|
||||
.appendField(new Blockly.FieldTextInput('OPTIONNAME'), 'CPU' + i);
|
||||
}
|
||||
}
|
||||
// Remove deleted options.
|
||||
while (this.getInput('OPTION' + i)) {
|
||||
this.removeInput('OPTION' + i);
|
||||
i++;
|
||||
}
|
||||
},
|
||||
onchange: function() {
|
||||
if (this.workspace && this.optionCount_ < 1) {
|
||||
this.setWarningText('Drop down menu must\nhave at least one option.');
|
||||
} else {
|
||||
fieldNameCheck(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['field_dropdown_container'] = {
|
||||
// Container.
|
||||
init: function() {
|
||||
this.setColour(160);
|
||||
this.appendDummyInput()
|
||||
.appendField('add options');
|
||||
this.appendStatementInput('STACK');
|
||||
this.setTooltip('Add, remove, or reorder options\n' +
|
||||
'to reconfigure this dropdown menu.');
|
||||
this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=386');
|
||||
this.contextMenu = false;
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['field_dropdown_option'] = {
|
||||
// Add option.
|
||||
init: function() {
|
||||
this.setColour(160);
|
||||
this.appendDummyInput()
|
||||
.appendField('option');
|
||||
this.setPreviousStatement(true);
|
||||
this.setNextStatement(true);
|
||||
this.setTooltip('Add a new option to the dropdown menu.');
|
||||
this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=386');
|
||||
this.contextMenu = false;
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['field_checkbox'] = {
|
||||
// Checkbox.
|
||||
init: function() {
|
||||
this.setColour(160);
|
||||
this.appendDummyInput()
|
||||
.appendField('checkbox')
|
||||
.appendField(new Blockly.FieldCheckbox('TRUE'), 'CHECKED')
|
||||
.appendField(',')
|
||||
.appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME');
|
||||
this.setPreviousStatement(true, 'Field');
|
||||
this.setNextStatement(true, 'Field');
|
||||
this.setTooltip('Checkbox field.');
|
||||
this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=485');
|
||||
},
|
||||
onchange: function() {
|
||||
fieldNameCheck(this);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['field_colour'] = {
|
||||
// Colour input.
|
||||
init: function() {
|
||||
this.setColour(160);
|
||||
this.appendDummyInput()
|
||||
.appendField('colour')
|
||||
.appendField(new Blockly.FieldColour('#ff0000'), 'COLOUR')
|
||||
.appendField(',')
|
||||
.appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME');
|
||||
this.setPreviousStatement(true, 'Field');
|
||||
this.setNextStatement(true, 'Field');
|
||||
this.setTooltip('Colour input field.');
|
||||
this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=495');
|
||||
},
|
||||
onchange: function() {
|
||||
fieldNameCheck(this);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['field_variable'] = {
|
||||
// Dropdown for variables.
|
||||
init: function() {
|
||||
this.setColour(160);
|
||||
this.appendDummyInput()
|
||||
.appendField('variable')
|
||||
.appendField(new Blockly.FieldTextInput('item'), 'TEXT')
|
||||
.appendField(',')
|
||||
.appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME');
|
||||
this.setPreviousStatement(true, 'Field');
|
||||
this.setNextStatement(true, 'Field');
|
||||
this.setTooltip('Dropdown menu for variable names.');
|
||||
this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=510');
|
||||
},
|
||||
onchange: function() {
|
||||
fieldNameCheck(this);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['field_image'] = {
|
||||
// Image.
|
||||
init: function() {
|
||||
this.setColour(160);
|
||||
var src = 'https://www.gstatic.com/codesite/ph/images/star_on.gif';
|
||||
this.appendDummyInput()
|
||||
.appendField('image')
|
||||
.appendField(new Blockly.FieldTextInput(src), 'SRC');
|
||||
this.appendDummyInput()
|
||||
.appendField('width')
|
||||
.appendField(new Blockly.FieldNumber('15', 0, NaN, 1), 'WIDTH')
|
||||
.appendField('height')
|
||||
.appendField(new Blockly.FieldNumber('15', 0, NaN, 1), 'HEIGHT')
|
||||
.appendField('alt text')
|
||||
.appendField(new Blockly.FieldTextInput('*'), 'ALT');
|
||||
this.setPreviousStatement(true, 'Field');
|
||||
this.setNextStatement(true, 'Field');
|
||||
this.setTooltip('Static image (JPEG, PNG, GIF, SVG, BMP).\n' +
|
||||
'Retains aspect ratio regardless of height and width.\n' +
|
||||
'Alt text is for when collapsed.');
|
||||
this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=567');
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['type_group'] = {
|
||||
// Group of types.
|
||||
init: function() {
|
||||
this.typeCount_ = 2;
|
||||
this.updateShape_();
|
||||
this.setOutput(true, 'Type');
|
||||
this.setMutator(new Blockly.icons.MutatorIcon(['type_group_item']));
|
||||
this.setColour(230);
|
||||
this.setTooltip('Allows more than one type to be accepted.');
|
||||
this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=677');
|
||||
},
|
||||
mutationToDom: function(workspace) {
|
||||
// Create XML to represent a group of types.
|
||||
var container = Blockly.utils.xml.createElement('mutation');
|
||||
container.setAttribute('types', this.typeCount_);
|
||||
return container;
|
||||
},
|
||||
domToMutation: function(container) {
|
||||
// Parse XML to restore the group of types.
|
||||
this.typeCount_ = parseInt(container.getAttribute('types'), 10);
|
||||
this.updateShape_();
|
||||
for (var i = 0; i < this.typeCount_; i++) {
|
||||
this.removeInput('TYPE' + i);
|
||||
}
|
||||
for (var i = 0; i < this.typeCount_; i++) {
|
||||
var input = this.appendValueInput('TYPE' + i)
|
||||
.setCheck('Type');
|
||||
if (i === 0) {
|
||||
input.appendField('any of');
|
||||
}
|
||||
}
|
||||
},
|
||||
decompose: function(workspace) {
|
||||
// Populate the mutator's dialog with this block's components.
|
||||
var containerBlock = workspace.newBlock('type_group_container');
|
||||
containerBlock.initSvg();
|
||||
var connection = containerBlock.getInput('STACK').connection;
|
||||
for (var i = 0; i < this.typeCount_; i++) {
|
||||
var typeBlock = workspace.newBlock('type_group_item');
|
||||
typeBlock.initSvg();
|
||||
connection.connect(typeBlock.previousConnection);
|
||||
connection = typeBlock.nextConnection;
|
||||
}
|
||||
return containerBlock;
|
||||
},
|
||||
compose: function(containerBlock) {
|
||||
// Reconfigure this block based on the mutator dialog's components.
|
||||
var typeBlock = containerBlock.getInputTargetBlock('STACK');
|
||||
// Count number of inputs.
|
||||
var connections = [];
|
||||
while (typeBlock) {
|
||||
connections.push(typeBlock.valueConnection_);
|
||||
typeBlock = typeBlock.nextConnection &&
|
||||
typeBlock.nextConnection.targetBlock();
|
||||
}
|
||||
// Disconnect any children that don't belong.
|
||||
for (var i = 0; i < this.typeCount_; i++) {
|
||||
var connection = this.getInput('TYPE' + i).connection.targetConnection;
|
||||
if (connection && connections.indexOf(connection) === -1) {
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
this.typeCount_ = connections.length;
|
||||
this.updateShape_();
|
||||
// Reconnect any child blocks.
|
||||
for (var i = 0; i < this.typeCount_; i++) {
|
||||
connections[i]?.reconnect(this, 'TYPE' + i);
|
||||
}
|
||||
},
|
||||
saveConnections: function(containerBlock) {
|
||||
// Store a pointer to any connected child blocks.
|
||||
var typeBlock = containerBlock.getInputTargetBlock('STACK');
|
||||
var i = 0;
|
||||
while (typeBlock) {
|
||||
var input = this.getInput('TYPE' + i);
|
||||
typeBlock.valueConnection_ = input && input.connection.targetConnection;
|
||||
i++;
|
||||
typeBlock = typeBlock.nextConnection &&
|
||||
typeBlock.nextConnection.targetBlock();
|
||||
}
|
||||
},
|
||||
updateShape_: function() {
|
||||
// Modify this block to have the correct number of inputs.
|
||||
// Add new inputs.
|
||||
for (var i = 0; i < this.typeCount_; i++) {
|
||||
if (!this.getInput('TYPE' + i)) {
|
||||
var input = this.appendValueInput('TYPE' + i);
|
||||
if (i === 0) {
|
||||
input.appendField('any of');
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remove deleted inputs.
|
||||
while (this.getInput('TYPE' + i)) {
|
||||
this.removeInput('TYPE' + i);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['type_group_container'] = {
|
||||
// Container.
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": "add types %1 %2",
|
||||
"args0": [
|
||||
{"type": "input_dummy"},
|
||||
{"type": "input_statement", "name": "STACK"}
|
||||
],
|
||||
"colour": 230,
|
||||
"tooltip": "Add, or remove allowed type.",
|
||||
"helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=677"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['type_group_item'] = {
|
||||
// Add type.
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": "type",
|
||||
"previousStatement": null,
|
||||
"nextStatement": null,
|
||||
"colour": 230,
|
||||
"tooltip": "Add a new allowed type.",
|
||||
"helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=677"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['type_null'] = {
|
||||
// Null type.
|
||||
valueType: null,
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": "any",
|
||||
"output": "Type",
|
||||
"colour": 230,
|
||||
"tooltip": "Any type is allowed.",
|
||||
"helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=602"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['type_boolean'] = {
|
||||
// Boolean type.
|
||||
valueType: 'Boolean',
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": "Boolean",
|
||||
"output": "Type",
|
||||
"colour": 230,
|
||||
"tooltip": "Booleans (true/false) are allowed.",
|
||||
"helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=602"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['type_number'] = {
|
||||
// Number type.
|
||||
valueType: 'Number',
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": "Number",
|
||||
"output": "Type",
|
||||
"colour": 230,
|
||||
"tooltip": "Numbers (int/float) are allowed.",
|
||||
"helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=602"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['type_string'] = {
|
||||
// String type.
|
||||
valueType: 'String',
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": "String",
|
||||
"output": "Type",
|
||||
"colour": 230,
|
||||
"tooltip": "Strings (text) are allowed.",
|
||||
"helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=602"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['type_list'] = {
|
||||
// List type.
|
||||
valueType: 'Array',
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": "Array",
|
||||
"output": "Type",
|
||||
"colour": 230,
|
||||
"tooltip": "Arrays (lists) are allowed.",
|
||||
"helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=602"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['type_other'] = {
|
||||
// Other type.
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": "other %1",
|
||||
"args0": [{"type": "field_input", "name": "TYPE", "text": ""}],
|
||||
"output": "Type",
|
||||
"colour": 230,
|
||||
"tooltip": "Custom type to allow.",
|
||||
"helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=702"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['colour_hue'] = {
|
||||
// Set the colour of the block.
|
||||
init: function() {
|
||||
this.appendDummyInput()
|
||||
.appendField('hue:')
|
||||
.appendField(new Blockly.FieldAngle('0', this.validator), 'HUE');
|
||||
this.setOutput(true, 'Colour');
|
||||
this.setTooltip('Paint the block with this colour.');
|
||||
this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=55');
|
||||
},
|
||||
validator: function(text) {
|
||||
// Update the current block's colour to match.
|
||||
var hue = parseInt(text, 10);
|
||||
if (!isNaN(hue)) {
|
||||
this.sourceBlock_.setColour(hue);
|
||||
}
|
||||
},
|
||||
mutationToDom: function(workspace) {
|
||||
var container = Blockly.utils.xml.createElement('mutation');
|
||||
container.setAttribute('colour', this.getColour());
|
||||
return container;
|
||||
},
|
||||
domToMutation: function(container) {
|
||||
this.setColour(container.getAttribute('colour'));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check to see if more than one field has this name.
|
||||
* Highly inefficient (On^2), but n is small.
|
||||
* @param {!Blockly.Block} referenceBlock Block to check.
|
||||
*/
|
||||
function fieldNameCheck(referenceBlock) {
|
||||
if (!referenceBlock.workspace) {
|
||||
// Block has been deleted.
|
||||
return;
|
||||
}
|
||||
var name = referenceBlock.getFieldValue('FIELDNAME').toLowerCase();
|
||||
var count = 0;
|
||||
var blocks = referenceBlock.workspace.getAllBlocks(false);
|
||||
for (var i = 0, block; block = blocks[i]; i++) {
|
||||
var otherName = block.getFieldValue('FIELDNAME');
|
||||
if (!block.disabled && !block.getInheritedDisabled() &&
|
||||
otherName && otherName.toLowerCase() === name) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
var msg = (count > 1) ?
|
||||
'There are ' + count + ' field blocks\n with this name.' : null;
|
||||
referenceBlock.setWarningText(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if more than one input has this name.
|
||||
* Highly inefficient (On^2), but n is small.
|
||||
* @param {!Blockly.Block} referenceBlock Block to check.
|
||||
*/
|
||||
function inputNameCheck(referenceBlock) {
|
||||
if (!referenceBlock.workspace) {
|
||||
// Block has been deleted.
|
||||
return;
|
||||
}
|
||||
var name = referenceBlock.getFieldValue('INPUTNAME').toLowerCase();
|
||||
var count = 0;
|
||||
var blocks = referenceBlock.workspace.getAllBlocks(false);
|
||||
for (var i = 0, block; block = blocks[i]; i++) {
|
||||
var otherName = block.getFieldValue('INPUTNAME');
|
||||
if (!block.disabled && !block.getInheritedDisabled() &&
|
||||
otherName && otherName.toLowerCase() === name) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
var msg = (count > 1) ?
|
||||
'There are ' + count + ' input blocks\n with this name.' : null;
|
||||
referenceBlock.setWarningText(msg);
|
||||
}
|
||||
@@ -1,819 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2012 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview JavaScript for Blockly's Block Factory application.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Workspace for user to build block.
|
||||
* @type {Blockly.Workspace}
|
||||
*/
|
||||
var mainWorkspace = null;
|
||||
|
||||
/**
|
||||
* Workspace for preview of block.
|
||||
* @type {Blockly.Workspace}
|
||||
*/
|
||||
var previewWorkspace = null;
|
||||
|
||||
/**
|
||||
* Name of block if not named.
|
||||
*/
|
||||
var UNNAMED = 'unnamed';
|
||||
|
||||
/**
|
||||
* Change the language code format.
|
||||
*/
|
||||
function formatChange() {
|
||||
var mask = document.getElementById('blocklyMask');
|
||||
var languagePre = document.getElementById('languagePre');
|
||||
var languageTA = document.getElementById('languageTA');
|
||||
if (document.getElementById('format').value === 'Manual') {
|
||||
Blockly.common.getMainWorkspace().hideChaff();
|
||||
mask.style.display = 'block';
|
||||
languagePre.style.display = 'none';
|
||||
languageTA.style.display = 'block';
|
||||
var code = languagePre.textContent.trim();
|
||||
languageTA.value = code;
|
||||
languageTA.focus();
|
||||
updatePreview();
|
||||
} else {
|
||||
mask.style.display = 'none';
|
||||
languageTA.style.display = 'none';
|
||||
languagePre.style.display = 'block';
|
||||
updateLanguage();
|
||||
}
|
||||
disableEnableLink();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the language code based on constructs made in Blockly.
|
||||
*/
|
||||
function updateLanguage() {
|
||||
var rootBlock = getRootBlock();
|
||||
if (!rootBlock) {
|
||||
return;
|
||||
}
|
||||
var blockType = rootBlock.getFieldValue('NAME').trim().toLowerCase();
|
||||
if (!blockType) {
|
||||
blockType = UNNAMED;
|
||||
}
|
||||
blockType = blockType.replace(/\W/g, '_').replace(/^(\d)/, '_\\1');
|
||||
switch (document.getElementById('format').value) {
|
||||
case 'JSON':
|
||||
var code = formatJson_(blockType, rootBlock);
|
||||
break;
|
||||
case 'JavaScript':
|
||||
var code = formatJavaScript_(blockType, rootBlock);
|
||||
break;
|
||||
}
|
||||
injectCode(code, 'languagePre');
|
||||
updatePreview();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the language code as JSON.
|
||||
* @param {string} blockType Name of block.
|
||||
* @param {!Blockly.Block} rootBlock Factory_base block.
|
||||
* @return {string} Generated language code.
|
||||
* @private
|
||||
*/
|
||||
function formatJson_(blockType, rootBlock) {
|
||||
var JS = {};
|
||||
// Type is not used by Blockly, but may be used by a loader.
|
||||
JS.type = blockType;
|
||||
// Generate inputs.
|
||||
var message = [];
|
||||
var args = [];
|
||||
var contentsBlock = rootBlock.getInputTargetBlock('INPUTS');
|
||||
var lastInput = null;
|
||||
while (contentsBlock) {
|
||||
if (!contentsBlock.disabled && !contentsBlock.getInheritedDisabled()) {
|
||||
var fields = getFieldsJson_(contentsBlock.getInputTargetBlock('FIELDS'));
|
||||
for (var i = 0; i < fields.length; i++) {
|
||||
if (typeof fields[i] === 'string') {
|
||||
message.push(fields[i].replace(/%/g, '%%'));
|
||||
} else {
|
||||
args.push(fields[i]);
|
||||
message.push('%' + args.length);
|
||||
}
|
||||
}
|
||||
|
||||
var input = {type: contentsBlock.type};
|
||||
// Dummy inputs don't have names. Other inputs do.
|
||||
if (contentsBlock.type !== 'input_dummy') {
|
||||
input.name = contentsBlock.getFieldValue('INPUTNAME');
|
||||
}
|
||||
var check = JSON.parse(getOptTypesFrom(contentsBlock, 'TYPE') || 'null');
|
||||
if (check) {
|
||||
input.check = check;
|
||||
}
|
||||
var align = contentsBlock.getFieldValue('ALIGN');
|
||||
if (align !== 'LEFT') {
|
||||
input.align = align;
|
||||
}
|
||||
args.push(input);
|
||||
message.push('%' + args.length);
|
||||
lastInput = contentsBlock;
|
||||
}
|
||||
contentsBlock = contentsBlock.nextConnection &&
|
||||
contentsBlock.nextConnection.targetBlock();
|
||||
}
|
||||
// Remove last input if dummy and not empty.
|
||||
if (lastInput && lastInput.type === 'input_dummy') {
|
||||
var fields = lastInput.getInputTargetBlock('FIELDS');
|
||||
if (fields && getFieldsJson_(fields).join('').trim() !== '') {
|
||||
var align = lastInput.getFieldValue('ALIGN');
|
||||
if (align !== 'LEFT') {
|
||||
JS.lastDummyAlign0 = align;
|
||||
}
|
||||
args.pop();
|
||||
message.pop();
|
||||
}
|
||||
}
|
||||
JS.message0 = message.join(' ');
|
||||
if (args.length) {
|
||||
JS.args0 = args;
|
||||
}
|
||||
// Generate inline/external switch.
|
||||
if (rootBlock.getFieldValue('INLINE') === 'EXT') {
|
||||
JS.inputsInline = false;
|
||||
} else if (rootBlock.getFieldValue('INLINE') === 'INT') {
|
||||
JS.inputsInline = true;
|
||||
}
|
||||
// Generate output, or next/previous connections.
|
||||
switch (rootBlock.getFieldValue('CONNECTIONS')) {
|
||||
case 'LEFT':
|
||||
JS.output =
|
||||
JSON.parse(getOptTypesFrom(rootBlock, 'OUTPUTTYPE') || 'null');
|
||||
break;
|
||||
case 'BOTH':
|
||||
JS.previousStatement =
|
||||
JSON.parse(getOptTypesFrom(rootBlock, 'TOPTYPE') || 'null');
|
||||
JS.nextStatement =
|
||||
JSON.parse(getOptTypesFrom(rootBlock, 'BOTTOMTYPE') || 'null');
|
||||
break;
|
||||
case 'TOP':
|
||||
JS.previousStatement =
|
||||
JSON.parse(getOptTypesFrom(rootBlock, 'TOPTYPE') || 'null');
|
||||
break;
|
||||
case 'BOTTOM':
|
||||
JS.nextStatement =
|
||||
JSON.parse(getOptTypesFrom(rootBlock, 'BOTTOMTYPE') || 'null');
|
||||
break;
|
||||
}
|
||||
// Generate colour.
|
||||
var colourBlock = rootBlock.getInputTargetBlock('COLOUR');
|
||||
if (colourBlock && !colourBlock.disabled) {
|
||||
var hue = parseInt(colourBlock.getFieldValue('HUE'), 10);
|
||||
JS.colour = hue;
|
||||
}
|
||||
JS.tooltip = '';
|
||||
JS.helpUrl = 'http://www.example.com/';
|
||||
return JSON.stringify(JS, null, ' ');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the language code as JavaScript.
|
||||
* @param {string} blockType Name of block.
|
||||
* @param {!Blockly.Block} rootBlock Factory_base block.
|
||||
* @return {string} Generated language code.
|
||||
* @private
|
||||
*/
|
||||
function formatJavaScript_(blockType, rootBlock) {
|
||||
var code = [];
|
||||
code.push("Blockly.Blocks['" + blockType + "'] = {");
|
||||
code.push(" init: function() {");
|
||||
// Generate inputs.
|
||||
var TYPES = {'input_value': 'appendValueInput',
|
||||
'input_statement': 'appendStatementInput',
|
||||
'input_dummy': 'appendDummyInput'};
|
||||
var contentsBlock = rootBlock.getInputTargetBlock('INPUTS');
|
||||
while (contentsBlock) {
|
||||
if (!contentsBlock.disabled && !contentsBlock.getInheritedDisabled()) {
|
||||
var name = '';
|
||||
// Dummy inputs don't have names. Other inputs do.
|
||||
if (contentsBlock.type !== 'input_dummy') {
|
||||
name = escapeString(contentsBlock.getFieldValue('INPUTNAME'));
|
||||
}
|
||||
code.push(' this.' + TYPES[contentsBlock.type] + '(' + name + ')');
|
||||
var check = getOptTypesFrom(contentsBlock, 'TYPE');
|
||||
if (check) {
|
||||
code.push(' .setCheck(' + check + ')');
|
||||
}
|
||||
var align = contentsBlock.getFieldValue('ALIGN');
|
||||
if (align !== 'LEFT') {
|
||||
code.push(' .setAlign(Blockly.ALIGN_' + align + ')');
|
||||
}
|
||||
var fields = getFieldsJs_(contentsBlock.getInputTargetBlock('FIELDS'));
|
||||
for (var i = 0; i < fields.length; i++) {
|
||||
code.push(' .appendField(' + fields[i] + ')');
|
||||
}
|
||||
// Add semicolon to last line to finish the statement.
|
||||
code[code.length - 1] += ';';
|
||||
}
|
||||
contentsBlock = contentsBlock.nextConnection &&
|
||||
contentsBlock.nextConnection.targetBlock();
|
||||
}
|
||||
// Generate inline/external switch.
|
||||
if (rootBlock.getFieldValue('INLINE') === 'EXT') {
|
||||
code.push(' this.setInputsInline(false);');
|
||||
} else if (rootBlock.getFieldValue('INLINE') === 'INT') {
|
||||
code.push(' this.setInputsInline(true);');
|
||||
}
|
||||
// Generate output, or next/previous connections.
|
||||
switch (rootBlock.getFieldValue('CONNECTIONS')) {
|
||||
case 'LEFT':
|
||||
code.push(connectionLineJs_('setOutput', 'OUTPUTTYPE'));
|
||||
break;
|
||||
case 'BOTH':
|
||||
code.push(connectionLineJs_('setPreviousStatement', 'TOPTYPE'));
|
||||
code.push(connectionLineJs_('setNextStatement', 'BOTTOMTYPE'));
|
||||
break;
|
||||
case 'TOP':
|
||||
code.push(connectionLineJs_('setPreviousStatement', 'TOPTYPE'));
|
||||
break;
|
||||
case 'BOTTOM':
|
||||
code.push(connectionLineJs_('setNextStatement', 'BOTTOMTYPE'));
|
||||
break;
|
||||
}
|
||||
// Generate colour.
|
||||
var colourBlock = rootBlock.getInputTargetBlock('COLOUR');
|
||||
if (colourBlock && !colourBlock.disabled) {
|
||||
var hue = parseInt(colourBlock.getFieldValue('HUE'), 10);
|
||||
if (!isNaN(hue)) {
|
||||
code.push(' this.setColour(' + hue + ');');
|
||||
}
|
||||
}
|
||||
code.push(" this.setTooltip('');");
|
||||
code.push(" this.setHelpUrl('http://www.example.com/');");
|
||||
code.push(' }');
|
||||
code.push('};');
|
||||
return code.join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create JS code required to create a top, bottom, or value connection.
|
||||
* @param {string} functionName JavaScript function name.
|
||||
* @param {string} typeName Name of type input.
|
||||
* @return {string} Line of JavaScript code to create connection.
|
||||
* @private
|
||||
*/
|
||||
function connectionLineJs_(functionName, typeName) {
|
||||
var type = getOptTypesFrom(getRootBlock(), typeName);
|
||||
if (type) {
|
||||
type = ', ' + type;
|
||||
} else {
|
||||
type = '';
|
||||
}
|
||||
return ' this.' + functionName + '(true' + type + ');';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns field strings and any config.
|
||||
* @param {!Blockly.Block} block Input block.
|
||||
* @return {!Array<string>} Field strings.
|
||||
* @private
|
||||
*/
|
||||
function getFieldsJs_(block) {
|
||||
var fields = [];
|
||||
while (block) {
|
||||
if (!block.disabled && !block.getInheritedDisabled()) {
|
||||
switch (block.type) {
|
||||
case 'field_static':
|
||||
// Result: 'hello'
|
||||
fields.push(escapeString(block.getFieldValue('TEXT')));
|
||||
break;
|
||||
case 'field_input':
|
||||
// Result: new Blockly.FieldTextInput('Hello'), 'GREET'
|
||||
fields.push('new Blockly.FieldTextInput(' +
|
||||
escapeString(block.getFieldValue('TEXT')) + '), ' +
|
||||
escapeString(block.getFieldValue('FIELDNAME')));
|
||||
break;
|
||||
case 'field_number':
|
||||
// Result: new Blockly.FieldNumber(10, 0, 100, 1), 'NUMBER'
|
||||
var args = [
|
||||
Number(block.getFieldValue('VALUE')),
|
||||
Number(block.getFieldValue('MIN')),
|
||||
Number(block.getFieldValue('MAX')),
|
||||
Number(block.getFieldValue('PRECISION'))
|
||||
];
|
||||
// Remove any trailing arguments that aren't needed.
|
||||
if (args[3] === 0) {
|
||||
args.pop();
|
||||
if (args[2] === Infinity) {
|
||||
args.pop();
|
||||
if (args[1] === -Infinity) {
|
||||
args.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
fields.push('new Blockly.FieldNumber(' + args.join(', ') + '), ' +
|
||||
escapeString(block.getFieldValue('FIELDNAME')));
|
||||
break;
|
||||
case 'field_angle':
|
||||
// Result: new Blockly.FieldAngle(90), 'ANGLE'
|
||||
fields.push('new Blockly.FieldAngle(' +
|
||||
Number(block.getFieldValue('ANGLE')) + '), ' +
|
||||
escapeString(block.getFieldValue('FIELDNAME')));
|
||||
break;
|
||||
case 'field_checkbox':
|
||||
// Result: new Blockly.FieldCheckbox('TRUE'), 'CHECK'
|
||||
fields.push('new Blockly.FieldCheckbox(' +
|
||||
escapeString(block.getFieldValue('CHECKED')) + '), ' +
|
||||
escapeString(block.getFieldValue('FIELDNAME')));
|
||||
break;
|
||||
case 'field_colour':
|
||||
// Result: new Blockly.FieldColour('#ff0000'), 'COLOUR'
|
||||
fields.push('new Blockly.FieldColour(' +
|
||||
escapeString(block.getFieldValue('COLOUR')) + '), ' +
|
||||
escapeString(block.getFieldValue('FIELDNAME')));
|
||||
break;
|
||||
case 'field_variable':
|
||||
// Result: new Blockly.FieldVariable('item'), 'VAR'
|
||||
var varname = escapeString(block.getFieldValue('TEXT') || null);
|
||||
fields.push('new Blockly.FieldVariable(' + varname + '), ' +
|
||||
escapeString(block.getFieldValue('FIELDNAME')));
|
||||
break;
|
||||
case 'field_dropdown':
|
||||
// Result:
|
||||
// new Blockly.FieldDropdown([['yes', '1'], ['no', '0']]), 'TOGGLE'
|
||||
var options = [];
|
||||
for (var i = 0; i < block.optionCount_; i++) {
|
||||
options[i] = '[' + escapeString(block.getFieldValue('USER' + i)) +
|
||||
', ' + escapeString(block.getFieldValue('CPU' + i)) + ']';
|
||||
}
|
||||
if (options.length) {
|
||||
fields.push('new Blockly.FieldDropdown([' +
|
||||
options.join(', ') + ']), ' +
|
||||
escapeString(block.getFieldValue('FIELDNAME')));
|
||||
}
|
||||
break;
|
||||
case 'field_image':
|
||||
// Result: new Blockly.FieldImage('http://...', 80, 60, '*')
|
||||
var src = escapeString(block.getFieldValue('SRC'));
|
||||
var width = Number(block.getFieldValue('WIDTH'));
|
||||
var height = Number(block.getFieldValue('HEIGHT'));
|
||||
var alt = escapeString(block.getFieldValue('ALT'));
|
||||
fields.push('new Blockly.FieldImage(' +
|
||||
src + ', ' + width + ', ' + height + ', ' + alt + ')');
|
||||
break;
|
||||
}
|
||||
}
|
||||
block = block.nextConnection && block.nextConnection.targetBlock();
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns field strings and any config.
|
||||
* @param {!Blockly.Block} block Input block.
|
||||
* @return {!Array<string|!Object>} Array of static text and field configs.
|
||||
* @private
|
||||
*/
|
||||
function getFieldsJson_(block) {
|
||||
var fields = [];
|
||||
while (block) {
|
||||
if (!block.disabled && !block.getInheritedDisabled()) {
|
||||
switch (block.type) {
|
||||
case 'field_static':
|
||||
// Result: 'hello'
|
||||
fields.push(block.getFieldValue('TEXT'));
|
||||
break;
|
||||
case 'field_input':
|
||||
fields.push({
|
||||
type: block.type,
|
||||
name: block.getFieldValue('FIELDNAME'),
|
||||
text: block.getFieldValue('TEXT')
|
||||
});
|
||||
break;
|
||||
case 'field_number':
|
||||
var obj = {
|
||||
type: block.type,
|
||||
name: block.getFieldValue('FIELDNAME'),
|
||||
value: Number(block.getFieldValue('VALUE'))
|
||||
};
|
||||
var min = Number(block.getFieldValue('MIN'));
|
||||
if (min > -Infinity) {
|
||||
obj.min = min;
|
||||
}
|
||||
var max = Number(block.getFieldValue('MAX'));
|
||||
if (max < Infinity) {
|
||||
obj.max = max;
|
||||
}
|
||||
var precision = Number(block.getFieldValue('PRECISION'));
|
||||
if (precision) {
|
||||
obj.precision = precision;
|
||||
}
|
||||
fields.push(obj);
|
||||
break;
|
||||
case 'field_angle':
|
||||
fields.push({
|
||||
type: block.type,
|
||||
name: block.getFieldValue('FIELDNAME'),
|
||||
angle: Number(block.getFieldValue('ANGLE'))
|
||||
});
|
||||
break;
|
||||
case 'field_checkbox':
|
||||
fields.push({
|
||||
type: block.type,
|
||||
name: block.getFieldValue('FIELDNAME'),
|
||||
checked: block.getFieldValue('CHECKED') === 'TRUE'
|
||||
});
|
||||
break;
|
||||
case 'field_colour':
|
||||
fields.push({
|
||||
type: block.type,
|
||||
name: block.getFieldValue('FIELDNAME'),
|
||||
colour: block.getFieldValue('COLOUR')
|
||||
});
|
||||
break;
|
||||
case 'field_variable':
|
||||
fields.push({
|
||||
type: block.type,
|
||||
name: block.getFieldValue('FIELDNAME'),
|
||||
variable: block.getFieldValue('TEXT') || null
|
||||
});
|
||||
break;
|
||||
case 'field_dropdown':
|
||||
var options = [];
|
||||
for (var i = 0; i < block.optionCount_; i++) {
|
||||
options[i] = [block.getFieldValue('USER' + i),
|
||||
block.getFieldValue('CPU' + i)];
|
||||
}
|
||||
if (options.length) {
|
||||
fields.push({
|
||||
type: block.type,
|
||||
name: block.getFieldValue('FIELDNAME'),
|
||||
options: options
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 'field_image':
|
||||
fields.push({
|
||||
type: block.type,
|
||||
src: block.getFieldValue('SRC'),
|
||||
width: Number(block.getFieldValue('WIDTH')),
|
||||
height: Number(block.getFieldValue('HEIGHT')),
|
||||
alt: block.getFieldValue('ALT')
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
block = block.nextConnection && block.nextConnection.targetBlock();
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape a string.
|
||||
* @param {string} string String to escape.
|
||||
* @return {string} Escaped string surrounded by quotes.
|
||||
*/
|
||||
function escapeString(string) {
|
||||
return JSON.stringify(string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the type(s) defined in the given input.
|
||||
* Format as a string for appending to the generated code.
|
||||
* @param {!Blockly.Block} block Block with input.
|
||||
* @param {string} name Name of the input.
|
||||
* @return {?string} String defining the types.
|
||||
*/
|
||||
function getOptTypesFrom(block, name) {
|
||||
var types = getTypesFrom_(block, name);
|
||||
if (types.length === 0) {
|
||||
return undefined;
|
||||
} else if (types.indexOf('null') !== -1) {
|
||||
return 'null';
|
||||
} else if (types.length === 1) {
|
||||
return types[0];
|
||||
} else {
|
||||
return '[' + types.join(', ') + ']';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the type(s) defined in the given input.
|
||||
* @param {!Blockly.Block} block Block with input.
|
||||
* @param {string} name Name of the input.
|
||||
* @return {!Array<string>} List of types.
|
||||
* @private
|
||||
*/
|
||||
function getTypesFrom_(block, name) {
|
||||
var typeBlock = block.getInputTargetBlock(name);
|
||||
var types;
|
||||
if (!typeBlock || typeBlock.disabled) {
|
||||
types = [];
|
||||
} else if (typeBlock.type === 'type_other') {
|
||||
types = [escapeString(typeBlock.getFieldValue('TYPE'))];
|
||||
} else if (typeBlock.type === 'type_group') {
|
||||
types = [];
|
||||
for (var i = 0; i < typeBlock.typeCount_; i++) {
|
||||
types = types.concat(getTypesFrom_(typeBlock, 'TYPE' + i));
|
||||
}
|
||||
// Remove duplicates.
|
||||
var hash = Object.create(null);
|
||||
for (var n = types.length - 1; n >= 0; n--) {
|
||||
if (hash[types[n]]) {
|
||||
types.splice(n, 1);
|
||||
}
|
||||
hash[types[n]] = true;
|
||||
}
|
||||
} else {
|
||||
types = [escapeString(typeBlock.valueType)];
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the generator code.
|
||||
* @param {!Blockly.Block} block Rendered block in preview workspace.
|
||||
*/
|
||||
function updateGenerator(block) {
|
||||
function makeVar(root, name) {
|
||||
name = name.toLowerCase().replace(/\W/g, '_');
|
||||
return ' var ' + root + '_' + name;
|
||||
}
|
||||
var language = document.getElementById('language').value;
|
||||
var code = [];
|
||||
code.push("Blockly." + language + "['" + block.type +
|
||||
"'] = function(block) {");
|
||||
|
||||
// Generate getters for any fields or inputs.
|
||||
for (var i = 0, input; input = block.inputList[i]; i++) {
|
||||
for (var j = 0, field; field = input.fieldRow[j]; j++) {
|
||||
var name = field.name;
|
||||
if (!name) {
|
||||
continue;
|
||||
}
|
||||
if (field instanceof Blockly.FieldVariable) {
|
||||
// Subclass of Blockly.FieldDropdown, must test first.
|
||||
code.push(makeVar('variable', name) +
|
||||
" = Blockly." + language +
|
||||
".nameDB_.getName(block.getFieldValue('" + name +
|
||||
"'), Blockly.Variables.NAME_TYPE);");
|
||||
} else if (field instanceof Blockly.FieldAngle) {
|
||||
// Subclass of Blockly.FieldTextInput, must test first.
|
||||
code.push(makeVar('angle', name) +
|
||||
" = block.getFieldValue('" + name + "');");
|
||||
} else if (field instanceof Blockly.FieldColour) {
|
||||
code.push(makeVar('colour', name) +
|
||||
" = block.getFieldValue('" + name + "');");
|
||||
} else if (field instanceof Blockly.FieldCheckbox) {
|
||||
code.push(makeVar('checkbox', name) +
|
||||
" = block.getFieldValue('" + name + "') === 'TRUE';");
|
||||
} else if (field instanceof Blockly.FieldDropdown) {
|
||||
code.push(makeVar('dropdown', name) +
|
||||
" = block.getFieldValue('" + name + "');");
|
||||
} else if (field instanceof Blockly.FieldNumber) {
|
||||
code.push(makeVar('number', name) +
|
||||
" = block.getFieldValue('" + name + "');");
|
||||
} else if (field instanceof Blockly.FieldTextInput) {
|
||||
code.push(makeVar('text', name) +
|
||||
" = block.getFieldValue('" + name + "');");
|
||||
}
|
||||
}
|
||||
var name = input.name;
|
||||
if (name) {
|
||||
if (input.type === Blockly.INPUT_VALUE) {
|
||||
code.push(makeVar('value', name) +
|
||||
" = Blockly." + language + ".valueToCode(block, '" + name +
|
||||
"', Blockly." + language + ".ORDER_ATOMIC);");
|
||||
} else if (input.type === Blockly.NEXT_STATEMENT) {
|
||||
code.push(makeVar('statements', name) +
|
||||
" = Blockly." + language + ".statementToCode(block, '" +
|
||||
name + "');");
|
||||
}
|
||||
}
|
||||
}
|
||||
// Most languages end lines with a semicolon. Python does not.
|
||||
var lineEnd = {
|
||||
'JavaScript': ';',
|
||||
'Python': '',
|
||||
'PHP': ';',
|
||||
'Dart': ';'
|
||||
};
|
||||
code.push(" // TODO: Assemble " + language + " into code variable.");
|
||||
if (block.outputConnection) {
|
||||
code.push(" var code = '...';");
|
||||
code.push(" // TODO: Change ORDER_NONE to the correct strength.");
|
||||
code.push(" return [code, Blockly." + language + ".ORDER_NONE];");
|
||||
} else {
|
||||
code.push(" var code = '..." + (lineEnd[language] || '') + "\\n';");
|
||||
code.push(" return code;");
|
||||
}
|
||||
code.push("};");
|
||||
|
||||
injectCode(code.join('\n'), 'generatorPre');
|
||||
}
|
||||
|
||||
/**
|
||||
* Existing direction ('ltr' vs 'rtl') of preview.
|
||||
*/
|
||||
var oldDir = null;
|
||||
|
||||
/**
|
||||
* Update the preview display.
|
||||
*/
|
||||
function updatePreview() {
|
||||
// Toggle between LTR/RTL if needed (also used in first display).
|
||||
var newDir = document.getElementById('direction').value;
|
||||
if (oldDir !== newDir) {
|
||||
if (previewWorkspace) {
|
||||
previewWorkspace.dispose();
|
||||
}
|
||||
var rtl = newDir === 'rtl';
|
||||
previewWorkspace = Blockly.inject('preview',
|
||||
{rtl: rtl,
|
||||
media: '../../media/',
|
||||
scrollbars: true});
|
||||
oldDir = newDir;
|
||||
}
|
||||
previewWorkspace.clear();
|
||||
|
||||
// Fetch the code and determine its format (JSON or JavaScript).
|
||||
var format = document.getElementById('format').value;
|
||||
if (format === 'Manual') {
|
||||
var code = document.getElementById('languageTA').value;
|
||||
// If the code is JSON, it will parse, otherwise treat as JS.
|
||||
try {
|
||||
JSON.parse(code);
|
||||
format = 'JSON';
|
||||
} catch (e) {
|
||||
format = 'JavaScript';
|
||||
}
|
||||
} else {
|
||||
var code = document.getElementById('languagePre').textContent;
|
||||
}
|
||||
if (!code.trim()) {
|
||||
// Nothing to render. Happens while cloud storage is loading.
|
||||
return;
|
||||
}
|
||||
|
||||
// Backup Blockly.Blocks object so that main workspace and preview don't
|
||||
// collide if user creates a 'factory_base' block, for instance.
|
||||
var backupBlocks = Blockly.Blocks;
|
||||
try {
|
||||
// Make a shallow copy.
|
||||
Blockly.Blocks = {};
|
||||
for (var prop in backupBlocks) {
|
||||
Blockly.Blocks[prop] = backupBlocks[prop];
|
||||
}
|
||||
|
||||
if (format === 'JSON') {
|
||||
var json = JSON.parse(code);
|
||||
Blockly.Blocks[json.type || UNNAMED] = {
|
||||
init: function() {
|
||||
this.jsonInit(json);
|
||||
}
|
||||
};
|
||||
} else if (format === 'JavaScript') {
|
||||
eval(code);
|
||||
} else {
|
||||
throw 'Unknown format: ' + format;
|
||||
}
|
||||
|
||||
// Look for a block on Blockly.Blocks that does not match the backup.
|
||||
var blockType = null;
|
||||
for (var type in Blockly.Blocks) {
|
||||
if (typeof Blockly.Blocks[type].init === 'function' &&
|
||||
Blockly.Blocks[type] !== backupBlocks[type]) {
|
||||
blockType = type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!blockType) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the preview block.
|
||||
var previewBlock = previewWorkspace.newBlock(blockType);
|
||||
previewBlock.initSvg();
|
||||
previewBlock.render();
|
||||
previewBlock.setMovable(false);
|
||||
previewBlock.setDeletable(false);
|
||||
previewBlock.moveBy(15, 10);
|
||||
previewWorkspace.clearUndo();
|
||||
|
||||
updateGenerator(previewBlock);
|
||||
} finally {
|
||||
Blockly.Blocks = backupBlocks;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject code into a pre tag, with syntax highlighting.
|
||||
* Safe from HTML/script injection.
|
||||
* @param {string} code Lines of code.
|
||||
* @param {string} id ID of <pre> element to inject into.
|
||||
*/
|
||||
function injectCode(code, id) {
|
||||
var pre = document.getElementById(id);
|
||||
pre.textContent = code;
|
||||
// Remove the 'prettyprinted' class, so that Prettify will recalculate.
|
||||
pre.className = pre.className.replace('prettyprinted', '');
|
||||
PR.prettyPrint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the uneditable container block that everything else attaches to.
|
||||
* @return {Blockly.Block}
|
||||
*/
|
||||
function getRootBlock() {
|
||||
var blocks = mainWorkspace.getTopBlocks(false);
|
||||
for (var i = 0, block; block = blocks[i]; i++) {
|
||||
if (block.type === 'factory_base') {
|
||||
return block;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the link button if the format is 'Manual', enable otherwise.
|
||||
*/
|
||||
function disableEnableLink() {
|
||||
var linkButton = document.getElementById('linkButton');
|
||||
linkButton.disabled = document.getElementById('format').value === 'Manual';
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize Blockly and layout. Called on page load.
|
||||
*/
|
||||
function init() {
|
||||
if ('BlocklyStorage' in window) {
|
||||
BlocklyStorage.HTTPREQUEST_ERROR =
|
||||
'There was a problem with the request.\n';
|
||||
BlocklyStorage.LINK_ALERT =
|
||||
'Share your blocks with this link:\n\n%1';
|
||||
BlocklyStorage.HASH_ERROR =
|
||||
'Sorry, "%1" doesn\'t correspond with any saved Blockly file.';
|
||||
BlocklyStorage.XML_ERROR = 'Could not load your saved file.\n'+
|
||||
'Perhaps it was created with a different version of Blockly?';
|
||||
var linkButton = document.getElementById('linkButton');
|
||||
linkButton.style.display = 'inline-block';
|
||||
linkButton.addEventListener('click',
|
||||
function() {BlocklyStorage.link(mainWorkspace);});
|
||||
disableEnableLink();
|
||||
}
|
||||
|
||||
document.getElementById('helpButton').addEventListener('click',
|
||||
function() {
|
||||
open('https://developers.google.com/blockly/guides/create-custom-blocks/block-factory',
|
||||
'BlockFactoryHelp');
|
||||
});
|
||||
|
||||
var expandList = [
|
||||
document.getElementById('blockly'),
|
||||
document.getElementById('blocklyMask'),
|
||||
document.getElementById('preview'),
|
||||
document.getElementById('languagePre'),
|
||||
document.getElementById('languageTA'),
|
||||
document.getElementById('generatorPre')
|
||||
];
|
||||
var onresize = function(e) {
|
||||
for (var i = 0, expand; expand = expandList[i]; i++) {
|
||||
expand.style.width = (expand.parentNode.offsetWidth - 2) + 'px';
|
||||
expand.style.height = (expand.parentNode.offsetHeight - 2) + 'px';
|
||||
}
|
||||
};
|
||||
onresize();
|
||||
window.addEventListener('resize', onresize);
|
||||
|
||||
var toolbox = document.getElementById('toolbox');
|
||||
mainWorkspace = Blockly.inject('blockly',
|
||||
{collapse: false,
|
||||
toolbox: toolbox,
|
||||
media: '../../media/'});
|
||||
|
||||
// Create the root block.
|
||||
if ('BlocklyStorage' in window && window.location.hash.length > 1) {
|
||||
BlocklyStorage.retrieveXml(window.location.hash.substring(1),
|
||||
mainWorkspace);
|
||||
} else {
|
||||
var xml = '<xml xmlns="https://developers.google.com/blockly/xml"><block type="factory_base" deletable="false" movable="false"></block></xml>';
|
||||
Blockly.Xml.domToWorkspace(Blockly.utils.xml.textToDom(xml), mainWorkspace);
|
||||
}
|
||||
mainWorkspace.clearUndo();
|
||||
|
||||
mainWorkspace.addChangeListener(Blockly.Events.disableOrphans);
|
||||
mainWorkspace.addChangeListener(updateLanguage);
|
||||
document.getElementById('direction')
|
||||
.addEventListener('change', updatePreview);
|
||||
document.getElementById('languageTA')
|
||||
.addEventListener('change', updatePreview);
|
||||
document.getElementById('languageTA')
|
||||
.addEventListener('keyup', updatePreview);
|
||||
document.getElementById('format')
|
||||
.addEventListener('change', formatChange);
|
||||
document.getElementById('language')
|
||||
.addEventListener('change', updatePreview);
|
||||
}
|
||||
window.addEventListener('load', init);
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.5 KiB |
@@ -1,224 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="target-densitydpi=device-dpi, height=660, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<title>Blockly Demo: Block Factory</title>
|
||||
<script src="/storage.js"></script>
|
||||
<script src="factory.js"></script>
|
||||
<script src="../../dist/blockly_compressed.js"></script>
|
||||
<script src="../../build/msg/en.js"></script>
|
||||
<script src="blocks.js"></script>
|
||||
<style>
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
background-color: #fff;
|
||||
font-family: sans-serif;
|
||||
margin: 0 5px;
|
||||
overflow: hidden
|
||||
}
|
||||
h1 {
|
||||
font-weight: normal;
|
||||
font-size: 140%;
|
||||
}
|
||||
h3 {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
table {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
td {
|
||||
vertical-align: top;
|
||||
padding: 0;
|
||||
}
|
||||
#blockly {
|
||||
position: fixed;
|
||||
}
|
||||
#blocklyMask {
|
||||
background-color: #000;
|
||||
cursor: not-allowed;
|
||||
display: none;
|
||||
position: fixed;
|
||||
opacity: 0.2;
|
||||
z-index: 9;
|
||||
}
|
||||
#preview {
|
||||
position: absolute;
|
||||
}
|
||||
pre,
|
||||
#languageTA {
|
||||
border: #ddd 1px solid;
|
||||
margin-top: 0;
|
||||
position: absolute;
|
||||
overflow: scroll;
|
||||
}
|
||||
#languageTA {
|
||||
display: none;
|
||||
font-family: monospace;
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ddd;
|
||||
background-color: #eee;
|
||||
color: #000;
|
||||
padding: 10px;
|
||||
margin: 0 5px;
|
||||
font-size: large;
|
||||
}
|
||||
button:hover:not(:disabled) {
|
||||
box-shadow: 2px 2px 5px #888;
|
||||
}
|
||||
button:disabled {
|
||||
opacity: 0.6;
|
||||
}
|
||||
button>* {
|
||||
opacity: 0.6;
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
button:hover:not(:disabled)>* {
|
||||
opacity: 1;
|
||||
}
|
||||
#linkButton {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<script src="https://cdn.jsdelivr.net/gh/google/code-prettify@master/loader/run_prettify.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<table>
|
||||
<tr>
|
||||
<td width="50%" height="5%">
|
||||
<h1><a href="https://developers.google.com/blockly/">Blockly</a> >
|
||||
<a href="../index.html">Demos</a> > Block Factory</h1>
|
||||
</td>
|
||||
<td width="50%" height="5%">
|
||||
<table>
|
||||
<tr>
|
||||
<td style="vertical-align: bottom;">
|
||||
<h3>Preview:
|
||||
<select id="direction">
|
||||
<option value="ltr">LTR</option>
|
||||
<option value="rtl">RTL</option>
|
||||
</select>
|
||||
</h3>
|
||||
</td>
|
||||
<td style="vertical-align: middle; text-align: right;">
|
||||
<button id="linkButton" title="Save and link to blocks.">
|
||||
<img src="link.png" height="21" width="21">
|
||||
</button>
|
||||
<button id="linkButton" title="Save and link to blocks.">
|
||||
<img src="link.png" height="21" width="21">
|
||||
</button>
|
||||
<button id="helpButton" title="View documentation in new window.">
|
||||
<span>Help</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" height="95%" style="padding: 2px;">
|
||||
<div id="blockly"></div>
|
||||
<div id="blocklyMask"></div>
|
||||
</td>
|
||||
<td width="50%" height="95%">
|
||||
<table>
|
||||
<tr>
|
||||
<td height="30%">
|
||||
<div id="preview"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height="5%">
|
||||
<h3>Language code:
|
||||
<select id="format">
|
||||
<option value="JSON">JSON</option>
|
||||
<option value="JavaScript">JavaScript</option>
|
||||
<option value="Manual">Manual edit…</option>
|
||||
</select>
|
||||
</h3>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height="30%">
|
||||
<pre id="languagePre" class="prettyprint lang-js"></pre>
|
||||
<textarea id="languageTA"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height="5%">
|
||||
<h3>Generator stub:
|
||||
<select id="language">
|
||||
<option value="JavaScript">JavaScript</option>
|
||||
<option value="Python">Python</option>
|
||||
<option value="PHP">PHP</option>
|
||||
<option value="Lua">Lua</option>
|
||||
<option value="Dart">Dart</option>
|
||||
</select>
|
||||
</h3>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height="30%">
|
||||
<pre id="generatorPre" class="prettyprint lang-js"></pre>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<xml xmlns="https://developers.google.com/blockly/xml" id="toolbox" style="display: none">
|
||||
<category name="Input">
|
||||
<block type="input_value">
|
||||
<value name="TYPE">
|
||||
<shadow type="type_null"></shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="input_statement">
|
||||
<value name="TYPE">
|
||||
<shadow type="type_null"></shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="input_dummy"></block>
|
||||
</category>
|
||||
<category name="Field">
|
||||
<block type="field_static"></block>
|
||||
<block type="field_input"></block>
|
||||
<block type="field_number"></block>
|
||||
<block type="field_angle"></block>
|
||||
<block type="field_dropdown"></block>
|
||||
<block type="field_checkbox"></block>
|
||||
<block type="field_colour"></block>
|
||||
<block type="field_variable"></block>
|
||||
<block type="field_image"></block>
|
||||
</category>
|
||||
<category name="Type">
|
||||
<block type="type_group"></block>
|
||||
<block type="type_null"></block>
|
||||
<block type="type_boolean"></block>
|
||||
<block type="type_number"></block>
|
||||
<block type="type_string"></block>
|
||||
<block type="type_list"></block>
|
||||
<block type="type_other"></block>
|
||||
</category>
|
||||
<category name="Colour" id="colourCategory">
|
||||
<block type="colour_hue"><mutation colour="20"></mutation><field name="HUE">20</field></block>
|
||||
<block type="colour_hue"><mutation colour="65"></mutation><field name="HUE">65</field></block>
|
||||
<block type="colour_hue"><mutation colour="120"></mutation><field name="HUE">120</field></block>
|
||||
<block type="colour_hue"><mutation colour="160"></mutation><field name="HUE">160</field></block>
|
||||
<block type="colour_hue"><mutation colour="210"></mutation><field name="HUE">210</field></block>
|
||||
<block type="colour_hue"><mutation colour="230"></mutation><field name="HUE">230</field></block>
|
||||
<block type="colour_hue"><mutation colour="260"></mutation><field name="HUE">260</field></block>
|
||||
<block type="colour_hue"><mutation colour="290"></mutation><field name="HUE">290</field></block>
|
||||
<block type="colour_hue"><mutation colour="330"></mutation><field name="HUE">330</field></block>
|
||||
</category>
|
||||
</xml>
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 228 B |
Reference in New Issue
Block a user