mirror of
https://github.com/google/blockly.git
synced 2026-01-07 00:50:27 +01:00
New initial commit with .svn directories and their contents ignored.
This commit is contained in:
99
blocks/colour.js
Normal file
99
blocks/colour.js
Normal file
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* Visual Blocks Editor
|
||||
*
|
||||
* Copyright 2012 Google Inc.
|
||||
* http://blockly.googlecode.com/
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Colour blocks for Blockly.
|
||||
* @author fraser@google.com (Neil Fraser)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Blocks.colour');
|
||||
|
||||
goog.require('Blockly.Blocks');
|
||||
|
||||
|
||||
Blockly.Blocks['colour_picker'] = {
|
||||
// Colour picker.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.COLOUR_PICKER_HELPURL);
|
||||
this.setColour(20);
|
||||
this.appendDummyInput()
|
||||
.appendTitle(new Blockly.FieldColour('#ff0000'), 'COLOUR');
|
||||
this.setOutput(true, 'Colour');
|
||||
this.setTooltip(Blockly.Msg.COLOUR_PICKER_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['colour_random'] = {
|
||||
// Random colour.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.COLOUR_RANDOM_HELPURL);
|
||||
this.setColour(20);
|
||||
this.appendDummyInput()
|
||||
.appendTitle(Blockly.Msg.COLOUR_RANDOM_TITLE);
|
||||
this.setOutput(true, 'Colour');
|
||||
this.setTooltip(Blockly.Msg.COLOUR_RANDOM_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['colour_rgb'] = {
|
||||
// Compose a colour from RGB components.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.COLOUR_RGB_HELPURL);
|
||||
this.setColour(20);
|
||||
this.appendValueInput('RED')
|
||||
.setCheck('Number')
|
||||
.setAlign(Blockly.ALIGN_RIGHT)
|
||||
.appendTitle(Blockly.Msg.COLOUR_RGB_TITLE)
|
||||
.appendTitle(Blockly.Msg.COLOUR_RGB_RED);
|
||||
this.appendValueInput('GREEN')
|
||||
.setCheck('Number')
|
||||
.setAlign(Blockly.ALIGN_RIGHT)
|
||||
.appendTitle(Blockly.Msg.COLOUR_RGB_GREEN);
|
||||
this.appendValueInput('BLUE')
|
||||
.setCheck('Number')
|
||||
.setAlign(Blockly.ALIGN_RIGHT)
|
||||
.appendTitle(Blockly.Msg.COLOUR_RGB_BLUE);
|
||||
this.setOutput(true, 'Colour');
|
||||
this.setTooltip(Blockly.Msg.COLOUR_RGB_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['colour_blend'] = {
|
||||
// Blend two colours together.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.COLOUR_BLEND_HELPURL);
|
||||
this.setColour(20);
|
||||
this.appendValueInput('COLOUR1')
|
||||
.setCheck('Colour')
|
||||
.setAlign(Blockly.ALIGN_RIGHT)
|
||||
.appendTitle(Blockly.Msg.COLOUR_BLEND_TITLE)
|
||||
.appendTitle(Blockly.Msg.COLOUR_BLEND_COLOUR1);
|
||||
this.appendValueInput('COLOUR2')
|
||||
.setCheck('Colour')
|
||||
.setAlign(Blockly.ALIGN_RIGHT)
|
||||
.appendTitle(Blockly.Msg.COLOUR_BLEND_COLOUR2);
|
||||
this.appendValueInput('RATIO')
|
||||
.setCheck('Number')
|
||||
.setAlign(Blockly.ALIGN_RIGHT)
|
||||
.appendTitle(Blockly.Msg.COLOUR_BLEND_RATIO);
|
||||
this.setOutput(true, 'Colour');
|
||||
this.setTooltip(Blockly.Msg.COLOUR_BLEND_TOOLTIP);
|
||||
}
|
||||
};
|
||||
499
blocks/lists.js
Normal file
499
blocks/lists.js
Normal file
@@ -0,0 +1,499 @@
|
||||
/**
|
||||
* Visual Blocks Editor
|
||||
*
|
||||
* Copyright 2012 Google Inc.
|
||||
* http://blockly.googlecode.com/
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview List blocks for Blockly.
|
||||
* @author fraser@google.com (Neil Fraser)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Blocks.lists');
|
||||
|
||||
goog.require('Blockly.Blocks');
|
||||
|
||||
|
||||
Blockly.Blocks['lists_create_empty'] = {
|
||||
// Create an empty list.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.LISTS_CREATE_EMPTY_HELPURL);
|
||||
this.setColour(260);
|
||||
this.setOutput(true, 'Array');
|
||||
this.appendDummyInput()
|
||||
.appendTitle(Blockly.Msg.LISTS_CREATE_EMPTY_TITLE);
|
||||
this.setTooltip(Blockly.Msg.LISTS_CREATE_EMPTY_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['lists_create_with'] = {
|
||||
// Create a list with any number of elements of any type.
|
||||
init: function() {
|
||||
this.setColour(260);
|
||||
this.appendValueInput('ADD0')
|
||||
.appendTitle(Blockly.Msg.LISTS_CREATE_WITH_INPUT_WITH);
|
||||
this.appendValueInput('ADD1');
|
||||
this.appendValueInput('ADD2');
|
||||
this.setOutput(true, 'Array');
|
||||
this.setMutator(new Blockly.Mutator(['lists_create_with_item']));
|
||||
this.setTooltip(Blockly.Msg.LISTS_CREATE_WITH_TOOLTIP);
|
||||
this.itemCount_ = 3;
|
||||
},
|
||||
mutationToDom: function(workspace) {
|
||||
var container = document.createElement('mutation');
|
||||
container.setAttribute('items', this.itemCount_);
|
||||
return container;
|
||||
},
|
||||
domToMutation: function(container) {
|
||||
for (var x = 0; x < this.itemCount_; x++) {
|
||||
this.removeInput('ADD' + x);
|
||||
}
|
||||
this.itemCount_ = parseInt(container.getAttribute('items'), 10);
|
||||
for (var x = 0; x < this.itemCount_; x++) {
|
||||
var input = this.appendValueInput('ADD' + x);
|
||||
if (x == 0) {
|
||||
input.appendTitle(Blockly.Msg.LISTS_CREATE_WITH_INPUT_WITH);
|
||||
}
|
||||
}
|
||||
if (this.itemCount_ == 0) {
|
||||
this.appendDummyInput('EMPTY')
|
||||
.appendTitle(Blockly.Msg.LISTS_CREATE_EMPTY_TITLE);
|
||||
}
|
||||
},
|
||||
decompose: function(workspace) {
|
||||
var containerBlock = new Blockly.Block(workspace,
|
||||
'lists_create_with_container');
|
||||
containerBlock.initSvg();
|
||||
var connection = containerBlock.getInput('STACK').connection;
|
||||
for (var x = 0; x < this.itemCount_; x++) {
|
||||
var itemBlock = new Blockly.Block(workspace, 'lists_create_with_item');
|
||||
itemBlock.initSvg();
|
||||
connection.connect(itemBlock.previousConnection);
|
||||
connection = itemBlock.nextConnection;
|
||||
}
|
||||
return containerBlock;
|
||||
},
|
||||
compose: function(containerBlock) {
|
||||
// Disconnect all input blocks and remove all inputs.
|
||||
if (this.itemCount_ == 0) {
|
||||
this.removeInput('EMPTY');
|
||||
} else {
|
||||
for (var x = this.itemCount_ - 1; x >= 0; x--) {
|
||||
this.removeInput('ADD' + x);
|
||||
}
|
||||
}
|
||||
this.itemCount_ = 0;
|
||||
// Rebuild the block's inputs.
|
||||
var itemBlock = containerBlock.getInputTargetBlock('STACK');
|
||||
while (itemBlock) {
|
||||
var input = this.appendValueInput('ADD' + this.itemCount_);
|
||||
if (this.itemCount_ == 0) {
|
||||
input.appendTitle(Blockly.Msg.LISTS_CREATE_WITH_INPUT_WITH);
|
||||
}
|
||||
// Reconnect any child blocks.
|
||||
if (itemBlock.valueConnection_) {
|
||||
input.connection.connect(itemBlock.valueConnection_);
|
||||
}
|
||||
this.itemCount_++;
|
||||
itemBlock = itemBlock.nextConnection &&
|
||||
itemBlock.nextConnection.targetBlock();
|
||||
}
|
||||
if (this.itemCount_ == 0) {
|
||||
this.appendDummyInput('EMPTY')
|
||||
.appendTitle(Blockly.Msg.LISTS_CREATE_EMPTY_TITLE);
|
||||
}
|
||||
},
|
||||
saveConnections: function(containerBlock) {
|
||||
// Store a pointer to any connected child blocks.
|
||||
var itemBlock = containerBlock.getInputTargetBlock('STACK');
|
||||
var x = 0;
|
||||
while (itemBlock) {
|
||||
var input = this.getInput('ADD' + x);
|
||||
itemBlock.valueConnection_ = input && input.connection.targetConnection;
|
||||
x++;
|
||||
itemBlock = itemBlock.nextConnection &&
|
||||
itemBlock.nextConnection.targetBlock();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['lists_create_with_container'] = {
|
||||
// Container.
|
||||
init: function() {
|
||||
this.setColour(260);
|
||||
this.appendDummyInput()
|
||||
.appendTitle(Blockly.Msg.LISTS_CREATE_WITH_CONTAINER_TITLE_ADD);
|
||||
this.appendStatementInput('STACK');
|
||||
this.setTooltip(Blockly.Msg.LISTS_CREATE_WITH_CONTAINER_TOOLTIP);
|
||||
this.contextMenu = false;
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['lists_create_with_item'] = {
|
||||
// Add items.
|
||||
init: function() {
|
||||
this.setColour(260);
|
||||
this.appendDummyInput()
|
||||
.appendTitle(Blockly.Msg.LISTS_CREATE_WITH_ITEM_TITLE);
|
||||
this.setPreviousStatement(true);
|
||||
this.setNextStatement(true);
|
||||
this.setTooltip(Blockly.Msg.LISTS_CREATE_WITH_ITEM_TOOLTIP);
|
||||
this.contextMenu = false;
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['lists_repeat'] = {
|
||||
// Create a list with one element repeated.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.LISTS_REPEAT_HELPURL);
|
||||
this.setColour(260);
|
||||
this.setOutput(true, 'Array');
|
||||
this.interpolateMsg(Blockly.Msg.LISTS_REPEAT_TITLE,
|
||||
['ITEM', null, Blockly.ALIGN_RIGHT],
|
||||
['NUM', 'Number', Blockly.ALIGN_RIGHT],
|
||||
Blockly.ALIGN_RIGHT);
|
||||
this.setTooltip(Blockly.Msg.LISTS_REPEAT_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['lists_length'] = {
|
||||
// List length.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.LISTS_LENGTH_HELPURL);
|
||||
this.setColour(260);
|
||||
this.interpolateMsg(Blockly.Msg.LISTS_LENGTH_TITLE,
|
||||
['VALUE', ['Array', 'String'], Blockly.ALIGN_RIGHT],
|
||||
Blockly.ALIGN_RIGHT);
|
||||
this.setOutput(true, 'Number');
|
||||
this.setTooltip(Blockly.Msg.LISTS_LENGTH_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['lists_isEmpty'] = {
|
||||
// Is the list empty?
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.LISTS_IS_EMPTY_HELPURL);
|
||||
this.setColour(260);
|
||||
this.interpolateMsg(Blockly.Msg.LISTS_IS_EMPTY_TITLE,
|
||||
['VALUE', ['Array', 'String'], Blockly.ALIGN_RIGHT],
|
||||
Blockly.ALIGN_RIGHT)
|
||||
this.setInputsInline(true);
|
||||
this.setOutput(true, 'Boolean');
|
||||
this.setTooltip(Blockly.Msg.LISTS_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['lists_indexOf'] = {
|
||||
// Find an item in the list.
|
||||
init: function() {
|
||||
var OPERATORS =
|
||||
[[Blockly.Msg.LISTS_INDEX_OF_FIRST, 'FIRST'],
|
||||
[Blockly.Msg.LISTS_INDEX_OF_LAST, 'LAST']];
|
||||
this.setHelpUrl(Blockly.Msg.LISTS_INDEX_OF_HELPURL);
|
||||
this.setColour(260);
|
||||
this.setOutput(true, 'Number');
|
||||
this.appendValueInput('VALUE')
|
||||
.setCheck('Array')
|
||||
.appendTitle(Blockly.Msg.LISTS_INDEX_OF_INPUT_IN_LIST);
|
||||
this.appendValueInput('FIND')
|
||||
.appendTitle(new Blockly.FieldDropdown(OPERATORS), 'END');
|
||||
this.setInputsInline(true);
|
||||
this.setTooltip(Blockly.Msg.LISTS_INDEX_OF_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['lists_getIndex'] = {
|
||||
// Get element at index.
|
||||
init: function() {
|
||||
var MODE =
|
||||
[[Blockly.Msg.LISTS_GET_INDEX_GET, 'GET'],
|
||||
[Blockly.Msg.LISTS_GET_INDEX_GET_REMOVE, 'GET_REMOVE'],
|
||||
[Blockly.Msg.LISTS_GET_INDEX_REMOVE, 'REMOVE']];
|
||||
this.WHERE_OPTIONS =
|
||||
[[Blockly.Msg.LISTS_GET_INDEX_FROM_START, 'FROM_START'],
|
||||
[Blockly.Msg.LISTS_GET_INDEX_FROM_END, 'FROM_END'],
|
||||
[Blockly.Msg.LISTS_GET_INDEX_FIRST, 'FIRST'],
|
||||
[Blockly.Msg.LISTS_GET_INDEX_LAST, 'LAST'],
|
||||
[Blockly.Msg.LISTS_GET_INDEX_RANDOM, 'RANDOM']];
|
||||
this.setHelpUrl(Blockly.Msg.LISTS_GET_INDEX_HELPURL);
|
||||
this.setColour(260);
|
||||
var modeMenu = new Blockly.FieldDropdown(MODE, function(value) {
|
||||
var isStatement = (value == 'REMOVE');
|
||||
this.sourceBlock_.updateStatement(isStatement);
|
||||
});
|
||||
this.appendValueInput('VALUE')
|
||||
.setCheck('Array')
|
||||
.appendTitle(Blockly.Msg.LISTS_GET_INDEX_INPUT_IN_LIST);
|
||||
this.appendDummyInput()
|
||||
.appendTitle(modeMenu, 'MODE')
|
||||
.appendTitle('', 'SPACE');
|
||||
this.appendDummyInput('AT');
|
||||
if (Blockly.Msg.LISTS_GET_INDEX_TAIL) {
|
||||
this.appendDummyInput('TAIL')
|
||||
.appendTitle(Blockly.Msg.LISTS_GET_INDEX_TAIL);
|
||||
}
|
||||
this.setInputsInline(true);
|
||||
this.setOutput(true);
|
||||
this.updateAt(true);
|
||||
// Assign 'this' to a variable for use in the tooltip closure below.
|
||||
var thisBlock = this;
|
||||
this.setTooltip(function() {
|
||||
var combo = thisBlock.getTitleValue('MODE') + '_' +
|
||||
thisBlock.getTitleValue('WHERE');
|
||||
return Blockly.Msg['LISTS_GET_INDEX_TOOLTIP_' + combo];
|
||||
});
|
||||
},
|
||||
mutationToDom: function() {
|
||||
// Save whether the block is a statement or a value.
|
||||
// Save whether there is an 'AT' input.
|
||||
var container = document.createElement('mutation');
|
||||
var isStatement = !this.outputConnection;
|
||||
container.setAttribute('statement', isStatement);
|
||||
var isAt = this.getInput('AT').type == Blockly.INPUT_VALUE;
|
||||
container.setAttribute('at', isAt);
|
||||
return container;
|
||||
},
|
||||
domToMutation: function(xmlElement) {
|
||||
// Restore the block shape.
|
||||
// Note: Until January 2013 this block did not have mutations,
|
||||
// so 'statement' defaults to false and 'at' defaults to true.
|
||||
var isStatement = (xmlElement.getAttribute('statement') == 'true');
|
||||
this.updateStatement(isStatement);
|
||||
var isAt = (xmlElement.getAttribute('at') != 'false');
|
||||
this.updateAt(isAt);
|
||||
},
|
||||
updateStatement: function(newStatement) {
|
||||
// Switch between a value block and a statement block.
|
||||
var oldStatement = !this.outputConnection;
|
||||
if (newStatement != oldStatement) {
|
||||
this.unplug(true, true);
|
||||
if (newStatement) {
|
||||
this.setOutput(false);
|
||||
this.setPreviousStatement(true);
|
||||
this.setNextStatement(true);
|
||||
} else {
|
||||
this.setPreviousStatement(false);
|
||||
this.setNextStatement(false);
|
||||
this.setOutput(true);
|
||||
}
|
||||
}
|
||||
},
|
||||
updateAt: function(isAt) {
|
||||
// Create or delete an input for the numeric index.
|
||||
// Destroy old 'AT' and 'ORDINAL' inputs.
|
||||
this.removeInput('AT');
|
||||
this.removeInput('ORDINAL', true);
|
||||
// Create either a value 'AT' input or a dummy input.
|
||||
if (isAt) {
|
||||
this.appendValueInput('AT').setCheck('Number');
|
||||
if (Blockly.Msg.ORDINAL_NUMBER_SUFFIX) {
|
||||
this.appendDummyInput('ORDINAL')
|
||||
.appendTitle(Blockly.Msg.ORDINAL_NUMBER_SUFFIX);
|
||||
}
|
||||
} else {
|
||||
this.appendDummyInput('AT');
|
||||
}
|
||||
var menu = new Blockly.FieldDropdown(this.WHERE_OPTIONS, function(value) {
|
||||
var newAt = (value == 'FROM_START') || (value == 'FROM_END');
|
||||
// The 'isAt' variable is available due to this function being a closure.
|
||||
if (newAt != isAt) {
|
||||
var block = this.sourceBlock_;
|
||||
block.updateAt(newAt);
|
||||
// This menu has been destroyed and replaced. Update the replacement.
|
||||
block.setTitleValue(value, 'WHERE');
|
||||
return null;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
this.getInput('AT').appendTitle(menu, 'WHERE');
|
||||
if (Blockly.Msg.LISTS_GET_INDEX_TAIL) {
|
||||
this.moveInputBefore('TAIL', null);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['lists_setIndex'] = {
|
||||
// Set element at index.
|
||||
init: function() {
|
||||
var MODE =
|
||||
[[Blockly.Msg.LISTS_SET_INDEX_SET, 'SET'],
|
||||
[Blockly.Msg.LISTS_SET_INDEX_INSERT, 'INSERT']];
|
||||
this.WHERE_OPTIONS =
|
||||
[[Blockly.Msg.LISTS_GET_INDEX_FROM_START, 'FROM_START'],
|
||||
[Blockly.Msg.LISTS_GET_INDEX_FROM_END, 'FROM_END'],
|
||||
[Blockly.Msg.LISTS_GET_INDEX_FIRST, 'FIRST'],
|
||||
[Blockly.Msg.LISTS_GET_INDEX_LAST, 'LAST'],
|
||||
[Blockly.Msg.LISTS_GET_INDEX_RANDOM, 'RANDOM']];
|
||||
this.setHelpUrl(Blockly.Msg.LISTS_SET_INDEX_HELPURL);
|
||||
this.setColour(260);
|
||||
this.appendValueInput('LIST')
|
||||
.setCheck('Array')
|
||||
.appendTitle(Blockly.Msg.LISTS_SET_INDEX_INPUT_IN_LIST);
|
||||
this.appendDummyInput()
|
||||
.appendTitle(new Blockly.FieldDropdown(MODE), 'MODE')
|
||||
.appendTitle('', 'SPACE');
|
||||
this.appendDummyInput('AT');
|
||||
this.appendValueInput('TO')
|
||||
.appendTitle(Blockly.Msg.LISTS_SET_INDEX_INPUT_TO);
|
||||
this.setInputsInline(true);
|
||||
this.setPreviousStatement(true);
|
||||
this.setNextStatement(true);
|
||||
this.setTooltip(Blockly.Msg.LISTS_SET_INDEX_TOOLTIP);
|
||||
this.updateAt(true);
|
||||
// Assign 'this' to a variable for use in the tooltip closure below.
|
||||
var thisBlock = this;
|
||||
this.setTooltip(function() {
|
||||
var combo = thisBlock.getTitleValue('MODE') + '_' +
|
||||
thisBlock.getTitleValue('WHERE');
|
||||
return Blockly.Msg['LISTS_SET_INDEX_TOOLTIP_' + combo];
|
||||
});
|
||||
},
|
||||
mutationToDom: function() {
|
||||
// Save whether there is an 'AT' input.
|
||||
var container = document.createElement('mutation');
|
||||
var isAt = this.getInput('AT').type == Blockly.INPUT_VALUE;
|
||||
container.setAttribute('at', isAt);
|
||||
return container;
|
||||
},
|
||||
domToMutation: function(xmlElement) {
|
||||
// Restore the block shape.
|
||||
// Note: Until January 2013 this block did not have mutations,
|
||||
// so 'at' defaults to true.
|
||||
var isAt = (xmlElement.getAttribute('at') != 'false');
|
||||
this.updateAt(isAt);
|
||||
},
|
||||
updateAt: function(isAt) {
|
||||
// Create or delete an input for the numeric index.
|
||||
// Destroy old 'AT' and 'ORDINAL' input.
|
||||
this.removeInput('AT');
|
||||
this.removeInput('ORDINAL', true);
|
||||
// Create either a value 'AT' input or a dummy input.
|
||||
if (isAt) {
|
||||
this.appendValueInput('AT').setCheck('Number');
|
||||
if (Blockly.Msg.ORDINAL_NUMBER_SUFFIX) {
|
||||
this.appendDummyInput('ORDINAL')
|
||||
.appendTitle(Blockly.Msg.ORDINAL_NUMBER_SUFFIX);
|
||||
}
|
||||
} else {
|
||||
this.appendDummyInput('AT');
|
||||
}
|
||||
var menu = new Blockly.FieldDropdown(this.WHERE_OPTIONS, function(value) {
|
||||
var newAt = (value == 'FROM_START') || (value == 'FROM_END');
|
||||
// The 'isAt' variable is available due to this function being a closure.
|
||||
if (newAt != isAt) {
|
||||
var block = this.sourceBlock_;
|
||||
block.updateAt(newAt);
|
||||
// This menu has been destroyed and replaced. Update the replacement.
|
||||
block.setTitleValue(value, 'WHERE');
|
||||
return null;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
this.moveInputBefore('AT', 'TO');
|
||||
if (this.getInput('ORDINAL')) {
|
||||
this.moveInputBefore('ORDINAL', 'TO');
|
||||
}
|
||||
|
||||
this.getInput('AT').appendTitle(menu, 'WHERE');
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['lists_getSublist'] = {
|
||||
// Get sublist.
|
||||
init: function() {
|
||||
this.WHERE_OPTIONS_1 =
|
||||
[[Blockly.Msg.LISTS_GET_SUBLIST_START_FROM_START, 'FROM_START'],
|
||||
[Blockly.Msg.LISTS_GET_SUBLIST_START_FROM_END, 'FROM_END'],
|
||||
[Blockly.Msg.LISTS_GET_SUBLIST_START_FIRST, 'FIRST']];
|
||||
this.WHERE_OPTIONS_2 =
|
||||
[[Blockly.Msg.LISTS_GET_SUBLIST_END_FROM_START, 'FROM_START'],
|
||||
[Blockly.Msg.LISTS_GET_SUBLIST_END_FROM_END, 'FROM_END'],
|
||||
[Blockly.Msg.LISTS_GET_SUBLIST_END_LAST, 'LAST']];
|
||||
this.setHelpUrl(Blockly.Msg.LISTS_GET_SUBLIST_HELPURL);
|
||||
this.setColour(260);
|
||||
this.appendValueInput('LIST')
|
||||
.setCheck('Array')
|
||||
.appendTitle(Blockly.Msg.LISTS_GET_SUBLIST_INPUT_IN_LIST);
|
||||
this.appendDummyInput('AT1');
|
||||
this.appendDummyInput('AT2');
|
||||
if (Blockly.Msg.LISTS_GET_SUBLIST_TAIL) {
|
||||
this.appendDummyInput('TAIL')
|
||||
.appendTitle(Blockly.Msg.LISTS_GET_SUBLIST_TAIL);
|
||||
}
|
||||
this.setInputsInline(true);
|
||||
this.setOutput(true, 'Array');
|
||||
this.updateAt(1, true);
|
||||
this.updateAt(2, true);
|
||||
this.setTooltip(Blockly.Msg.LISTS_GET_SUBLIST_TOOLTIP);
|
||||
},
|
||||
mutationToDom: function() {
|
||||
// Save whether there are 'AT' inputs.
|
||||
var container = document.createElement('mutation');
|
||||
var isAt1 = this.getInput('AT1').type == Blockly.INPUT_VALUE;
|
||||
container.setAttribute('at1', isAt1);
|
||||
var isAt2 = this.getInput('AT2').type == Blockly.INPUT_VALUE;
|
||||
container.setAttribute('at2', isAt2);
|
||||
return container;
|
||||
},
|
||||
domToMutation: function(xmlElement) {
|
||||
// Restore the block shape.
|
||||
var isAt1 = (xmlElement.getAttribute('at1') == 'true');
|
||||
var isAt2 = (xmlElement.getAttribute('at2') == 'true');
|
||||
this.updateAt(1, isAt1);
|
||||
this.updateAt(2, isAt2);
|
||||
},
|
||||
updateAt: function(n, isAt) {
|
||||
// Create or delete an input for the numeric index.
|
||||
// Destroy old 'AT' and 'ORDINAL' inputs.
|
||||
this.removeInput('AT' + n);
|
||||
this.removeInput('ORDINAL' + n, true);
|
||||
// Create either a value 'AT' input or a dummy input.
|
||||
if (isAt) {
|
||||
this.appendValueInput('AT' + n).setCheck('Number');
|
||||
if (Blockly.Msg.ORDINAL_NUMBER_SUFFIX) {
|
||||
this.appendDummyInput('ORDINAL' + n)
|
||||
.appendTitle(Blockly.Msg.ORDINAL_NUMBER_SUFFIX);
|
||||
}
|
||||
} else {
|
||||
this.appendDummyInput('AT' + n);
|
||||
}
|
||||
var menu = new Blockly.FieldDropdown(this['WHERE_OPTIONS_' + n],
|
||||
function(value) {
|
||||
var newAt = (value == 'FROM_START') || (value == 'FROM_END');
|
||||
// The 'isAt' variable is available due to this function being a closure.
|
||||
if (newAt != isAt) {
|
||||
var block = this.sourceBlock_;
|
||||
block.updateAt(n, newAt);
|
||||
// This menu has been destroyed and replaced. Update the replacement.
|
||||
block.setTitleValue(value, 'WHERE' + n);
|
||||
return null;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
this.getInput('AT' + n)
|
||||
.appendTitle(menu, 'WHERE' + n);
|
||||
if (n == 1) {
|
||||
this.moveInputBefore('AT1', 'AT2');
|
||||
if (this.getInput('ORDINAL1')) {
|
||||
this.moveInputBefore('ORDINAL1', 'AT2');
|
||||
}
|
||||
}
|
||||
if (Blockly.Msg.LISTS_GET_SUBLIST_TAIL) {
|
||||
this.moveInputBefore('TAIL', null);
|
||||
}
|
||||
}
|
||||
};
|
||||
350
blocks/logic.js
Normal file
350
blocks/logic.js
Normal file
@@ -0,0 +1,350 @@
|
||||
/**
|
||||
* Visual Blocks Editor
|
||||
*
|
||||
* Copyright 2012 Google Inc.
|
||||
* http://blockly.googlecode.com/
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Logic blocks for Blockly.
|
||||
* @author q.neutron@gmail.com (Quynh Neutron)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Blocks.logic');
|
||||
|
||||
goog.require('Blockly.Blocks');
|
||||
|
||||
|
||||
Blockly.Blocks['controls_if'] = {
|
||||
// If/elseif/else condition.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.CONTROLS_IF_HELPURL);
|
||||
this.setColour(210);
|
||||
this.appendValueInput('IF0')
|
||||
.setCheck('Boolean')
|
||||
.appendTitle(Blockly.Msg.CONTROLS_IF_MSG_IF);
|
||||
this.appendStatementInput('DO0')
|
||||
.appendTitle(Blockly.Msg.CONTROLS_IF_MSG_THEN);
|
||||
this.setPreviousStatement(true);
|
||||
this.setNextStatement(true);
|
||||
this.setMutator(new Blockly.Mutator(['controls_if_elseif',
|
||||
'controls_if_else']));
|
||||
// Assign 'this' to a variable for use in the tooltip closure below.
|
||||
var thisBlock = this;
|
||||
this.setTooltip(function() {
|
||||
if (!thisBlock.elseifCount_ && !thisBlock.elseCount_) {
|
||||
return Blockly.Msg.CONTROLS_IF_TOOLTIP_1;
|
||||
} else if (!thisBlock.elseifCount_ && thisBlock.elseCount_) {
|
||||
return Blockly.Msg.CONTROLS_IF_TOOLTIP_2;
|
||||
} else if (thisBlock.elseifCount_ && !thisBlock.elseCount_) {
|
||||
return Blockly.Msg.CONTROLS_IF_TOOLTIP_3;
|
||||
} else if (thisBlock.elseifCount_ && thisBlock.elseCount_) {
|
||||
return Blockly.Msg.CONTROLS_IF_TOOLTIP_4;
|
||||
}
|
||||
return '';
|
||||
});
|
||||
this.elseifCount_ = 0;
|
||||
this.elseCount_ = 0;
|
||||
},
|
||||
mutationToDom: function() {
|
||||
if (!this.elseifCount_ && !this.elseCount_) {
|
||||
return null;
|
||||
}
|
||||
var container = document.createElement('mutation');
|
||||
if (this.elseifCount_) {
|
||||
container.setAttribute('elseif', this.elseifCount_);
|
||||
}
|
||||
if (this.elseCount_) {
|
||||
container.setAttribute('else', 1);
|
||||
}
|
||||
return container;
|
||||
},
|
||||
domToMutation: function(xmlElement) {
|
||||
this.elseifCount_ = parseInt(xmlElement.getAttribute('elseif'), 10);
|
||||
this.elseCount_ = parseInt(xmlElement.getAttribute('else'), 10);
|
||||
for (var x = 1; x <= this.elseifCount_; x++) {
|
||||
this.appendValueInput('IF' + x)
|
||||
.setCheck('Boolean')
|
||||
.appendTitle(Blockly.Msg.CONTROLS_IF_MSG_ELSEIF);
|
||||
this.appendStatementInput('DO' + x)
|
||||
.appendTitle(Blockly.Msg.CONTROLS_IF_MSG_THEN);
|
||||
}
|
||||
if (this.elseCount_) {
|
||||
this.appendStatementInput('ELSE')
|
||||
.appendTitle(Blockly.Msg.CONTROLS_IF_MSG_ELSE);
|
||||
}
|
||||
},
|
||||
decompose: function(workspace) {
|
||||
var containerBlock = new Blockly.Block(workspace, 'controls_if_if');
|
||||
containerBlock.initSvg();
|
||||
var connection = containerBlock.getInput('STACK').connection;
|
||||
for (var x = 1; x <= this.elseifCount_; x++) {
|
||||
var elseifBlock = new Blockly.Block(workspace, 'controls_if_elseif');
|
||||
elseifBlock.initSvg();
|
||||
connection.connect(elseifBlock.previousConnection);
|
||||
connection = elseifBlock.nextConnection;
|
||||
}
|
||||
if (this.elseCount_) {
|
||||
var elseBlock = new Blockly.Block(workspace, 'controls_if_else');
|
||||
elseBlock.initSvg();
|
||||
connection.connect(elseBlock.previousConnection);
|
||||
}
|
||||
return containerBlock;
|
||||
},
|
||||
compose: function(containerBlock) {
|
||||
// Disconnect the else input blocks and remove the inputs.
|
||||
if (this.elseCount_) {
|
||||
this.removeInput('ELSE');
|
||||
}
|
||||
this.elseCount_ = 0;
|
||||
// Disconnect all the elseif input blocks and remove the inputs.
|
||||
for (var x = this.elseifCount_; x > 0; x--) {
|
||||
this.removeInput('IF' + x);
|
||||
this.removeInput('DO' + x);
|
||||
}
|
||||
this.elseifCount_ = 0;
|
||||
// Rebuild the block's optional inputs.
|
||||
var clauseBlock = containerBlock.getInputTargetBlock('STACK');
|
||||
while (clauseBlock) {
|
||||
switch (clauseBlock.type) {
|
||||
case 'controls_if_elseif':
|
||||
this.elseifCount_++;
|
||||
var ifInput = this.appendValueInput('IF' + this.elseifCount_)
|
||||
.setCheck('Boolean')
|
||||
.appendTitle(Blockly.Msg.CONTROLS_IF_MSG_ELSEIF);
|
||||
var doInput = this.appendStatementInput('DO' + this.elseifCount_);
|
||||
doInput.appendTitle(Blockly.Msg.CONTROLS_IF_MSG_THEN);
|
||||
// Reconnect any child blocks.
|
||||
if (clauseBlock.valueConnection_) {
|
||||
ifInput.connection.connect(clauseBlock.valueConnection_);
|
||||
}
|
||||
if (clauseBlock.statementConnection_) {
|
||||
doInput.connection.connect(clauseBlock.statementConnection_);
|
||||
}
|
||||
break;
|
||||
case 'controls_if_else':
|
||||
this.elseCount_++;
|
||||
var elseInput = this.appendStatementInput('ELSE');
|
||||
elseInput.appendTitle(Blockly.Msg.CONTROLS_IF_MSG_ELSE);
|
||||
// Reconnect any child blocks.
|
||||
if (clauseBlock.statementConnection_) {
|
||||
elseInput.connection.connect(clauseBlock.statementConnection_);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw 'Unknown block type.';
|
||||
}
|
||||
clauseBlock = clauseBlock.nextConnection &&
|
||||
clauseBlock.nextConnection.targetBlock();
|
||||
}
|
||||
},
|
||||
saveConnections: function(containerBlock) {
|
||||
// Store a pointer to any connected child blocks.
|
||||
var clauseBlock = containerBlock.getInputTargetBlock('STACK');
|
||||
var x = 1;
|
||||
while (clauseBlock) {
|
||||
switch (clauseBlock.type) {
|
||||
case 'controls_if_elseif':
|
||||
var inputIf = this.getInput('IF' + x);
|
||||
var inputDo = this.getInput('DO' + x);
|
||||
clauseBlock.valueConnection_ =
|
||||
inputIf && inputIf.connection.targetConnection;
|
||||
clauseBlock.statementConnection_ =
|
||||
inputDo && inputDo.connection.targetConnection;
|
||||
x++;
|
||||
break;
|
||||
case 'controls_if_else':
|
||||
var inputDo = this.getInput('ELSE');
|
||||
clauseBlock.statementConnection_ =
|
||||
inputDo && inputDo.connection.targetConnection;
|
||||
break;
|
||||
default:
|
||||
throw 'Unknown block type.';
|
||||
}
|
||||
clauseBlock = clauseBlock.nextConnection &&
|
||||
clauseBlock.nextConnection.targetBlock();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['controls_if_if'] = {
|
||||
// If condition.
|
||||
init: function() {
|
||||
this.setColour(210);
|
||||
this.appendDummyInput()
|
||||
.appendTitle(Blockly.Msg.CONTROLS_IF_IF_TITLE_IF);
|
||||
this.appendStatementInput('STACK');
|
||||
this.setTooltip(Blockly.Msg.CONTROLS_IF_IF_TOOLTIP);
|
||||
this.contextMenu = false;
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['controls_if_elseif'] = {
|
||||
// Else-If condition.
|
||||
init: function() {
|
||||
this.setColour(210);
|
||||
this.appendDummyInput()
|
||||
.appendTitle(Blockly.Msg.CONTROLS_IF_ELSEIF_TITLE_ELSEIF);
|
||||
this.setPreviousStatement(true);
|
||||
this.setNextStatement(true);
|
||||
this.setTooltip(Blockly.Msg.CONTROLS_IF_ELSEIF_TOOLTIP);
|
||||
this.contextMenu = false;
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['controls_if_else'] = {
|
||||
// Else condition.
|
||||
init: function() {
|
||||
this.setColour(210);
|
||||
this.appendDummyInput()
|
||||
.appendTitle(Blockly.Msg.CONTROLS_IF_ELSE_TITLE_ELSE);
|
||||
this.setPreviousStatement(true);
|
||||
this.setTooltip(Blockly.Msg.CONTROLS_IF_ELSE_TOOLTIP);
|
||||
this.contextMenu = false;
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['logic_compare'] = {
|
||||
// Comparison operator.
|
||||
init: function() {
|
||||
if (Blockly.RTL) {
|
||||
var OPERATORS = [
|
||||
['=', 'EQ'],
|
||||
['\u2260', 'NEQ'],
|
||||
['>', 'LT'],
|
||||
['\u2265', 'LTE'],
|
||||
['<', 'GT'],
|
||||
['\u2264', 'GTE']
|
||||
];
|
||||
} else {
|
||||
var OPERATORS = [
|
||||
['=', 'EQ'],
|
||||
['\u2260', 'NEQ'],
|
||||
['<', 'LT'],
|
||||
['\u2264', 'LTE'],
|
||||
['>', 'GT'],
|
||||
['\u2265', 'GTE']
|
||||
];
|
||||
}
|
||||
this.setHelpUrl(Blockly.Msg.LOGIC_COMPARE_HELPURL);
|
||||
this.setColour(210);
|
||||
this.setOutput(true, 'Boolean');
|
||||
this.appendValueInput('A');
|
||||
this.appendValueInput('B')
|
||||
.appendTitle(new Blockly.FieldDropdown(OPERATORS), 'OP');
|
||||
this.setInputsInline(true);
|
||||
// Assign 'this' to a variable for use in the tooltip closure below.
|
||||
var thisBlock = this;
|
||||
this.setTooltip(function() {
|
||||
var op = thisBlock.getTitleValue('OP');
|
||||
var TOOLTIPS = {
|
||||
EQ: Blockly.Msg.LOGIC_COMPARE_TOOLTIP_EQ,
|
||||
NEQ: Blockly.Msg.LOGIC_COMPARE_TOOLTIP_NEQ,
|
||||
LT: Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LT,
|
||||
LTE: Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LTE,
|
||||
GT: Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GT,
|
||||
GTE: Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GTE
|
||||
};
|
||||
return TOOLTIPS[op];
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['logic_operation'] = {
|
||||
// Logical operations: 'and', 'or'.
|
||||
init: function() {
|
||||
var OPERATORS =
|
||||
[[Blockly.Msg.LOGIC_OPERATION_AND, 'AND'],
|
||||
[Blockly.Msg.LOGIC_OPERATION_OR, 'OR']];
|
||||
this.setHelpUrl(Blockly.Msg.LOGIC_OPERATION_HELPURL);
|
||||
this.setColour(210);
|
||||
this.setOutput(true, 'Boolean');
|
||||
this.appendValueInput('A')
|
||||
.setCheck('Boolean');
|
||||
this.appendValueInput('B')
|
||||
.setCheck('Boolean')
|
||||
.appendTitle(new Blockly.FieldDropdown(OPERATORS), 'OP');
|
||||
this.setInputsInline(true);
|
||||
// Assign 'this' to a variable for use in the tooltip closure below.
|
||||
var thisBlock = this;
|
||||
this.setTooltip(function() {
|
||||
var op = thisBlock.getTitleValue('OP');
|
||||
var TOOLTIPS = {
|
||||
AND: Blockly.Msg.LOGIC_OPERATION_TOOLTIP_AND,
|
||||
OR: Blockly.Msg.LOGIC_OPERATION_TOOLTIP_OR
|
||||
};
|
||||
return thisBlock.TOOLTIPS[op];
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Blockly.Blocks['logic_negate'] = {
|
||||
// Negation.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.LOGIC_NEGATE_HELPURL);
|
||||
this.setColour(210);
|
||||
this.setOutput(true, 'Boolean');
|
||||
this.interpolateMsg(Blockly.Msg.LOGIC_NEGATE_TITLE,
|
||||
['BOOL', 'Boolean', Blockly.ALIGN_RIGHT],
|
||||
Blockly.ALIGN_RIGHT)
|
||||
this.setTooltip(Blockly.Msg.LOGIC_NEGATE_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['logic_boolean'] = {
|
||||
// Boolean data type: true and false.
|
||||
init: function() {
|
||||
var BOOLEANS =
|
||||
[[Blockly.Msg.LOGIC_BOOLEAN_TRUE, 'TRUE'],
|
||||
[Blockly.Msg.LOGIC_BOOLEAN_FALSE, 'FALSE']];
|
||||
this.setHelpUrl(Blockly.Msg.LOGIC_BOOLEAN_HELPURL);
|
||||
this.setColour(210);
|
||||
this.setOutput(true, 'Boolean');
|
||||
this.appendDummyInput()
|
||||
.appendTitle(new Blockly.FieldDropdown(BOOLEANS), 'BOOL');
|
||||
this.setTooltip(Blockly.Msg.LOGIC_BOOLEAN_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['logic_null'] = {
|
||||
// Null data type.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.LOGIC_NULL_HELPURL);
|
||||
this.setColour(210);
|
||||
this.setOutput(true);
|
||||
this.appendDummyInput()
|
||||
.appendTitle(Blockly.Msg.LOGIC_NULL);
|
||||
this.setTooltip(Blockly.Msg.LOGIC_NULL_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['logic_ternary'] = {
|
||||
// Ternary operator.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.LOGIC_TERNARY_HELPURL);
|
||||
this.setColour(210);
|
||||
this.appendValueInput('IF')
|
||||
.setCheck('Boolean')
|
||||
.appendTitle(Blockly.Msg.LOGIC_TERNARY_CONDITION);
|
||||
this.appendValueInput('THEN')
|
||||
.appendTitle(Blockly.Msg.LOGIC_TERNARY_IF_TRUE);
|
||||
this.appendValueInput('ELSE')
|
||||
.appendTitle(Blockly.Msg.LOGIC_TERNARY_IF_FALSE);
|
||||
this.setOutput(true);
|
||||
this.setTooltip(Blockly.Msg.LOGIC_TERNARY_TOOLTIP);
|
||||
}
|
||||
};
|
||||
224
blocks/loops.js
Normal file
224
blocks/loops.js
Normal file
@@ -0,0 +1,224 @@
|
||||
/**
|
||||
* Visual Blocks Editor
|
||||
*
|
||||
* Copyright 2012 Google Inc.
|
||||
* http://blockly.googlecode.com/
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Loop blocks for Blockly.
|
||||
* @author fraser@google.com (Neil Fraser)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Blocks.loops');
|
||||
|
||||
goog.require('Blockly.Blocks');
|
||||
|
||||
|
||||
Blockly.Blocks['controls_repeat'] = {
|
||||
// Repeat n times (internal number).
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.CONTROLS_REPEAT_HELPURL);
|
||||
this.setColour(120);
|
||||
this.appendDummyInput()
|
||||
.appendTitle(Blockly.Msg.CONTROLS_REPEAT_TITLE_REPEAT)
|
||||
.appendTitle(new Blockly.FieldTextInput('10',
|
||||
Blockly.FieldTextInput.nonnegativeIntegerValidator), 'TIMES')
|
||||
.appendTitle(Blockly.Msg.CONTROLS_REPEAT_TITLE_TIMES);
|
||||
this.appendStatementInput('DO')
|
||||
.appendTitle(Blockly.Msg.CONTROLS_REPEAT_INPUT_DO);
|
||||
this.setPreviousStatement(true);
|
||||
this.setNextStatement(true);
|
||||
this.setTooltip(Blockly.Msg.CONTROLS_REPEAT_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['controls_repeat_ext'] = {
|
||||
// Repeat n times (external number).
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.CONTROLS_REPEAT_HELPURL);
|
||||
this.setColour(120);
|
||||
this.interpolateMsg(Blockly.Msg.CONTROLS_REPEAT_TITLE,
|
||||
['TIMES', 'Number', Blockly.ALIGN_RIGHT],
|
||||
Blockly.ALIGN_RIGHT);
|
||||
this.appendStatementInput('DO')
|
||||
.appendTitle(Blockly.Msg.CONTROLS_REPEAT_INPUT_DO);
|
||||
this.setPreviousStatement(true);
|
||||
this.setNextStatement(true);
|
||||
this.setInputsInline(true);
|
||||
this.setTooltip(Blockly.Msg.CONTROLS_REPEAT_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['controls_whileUntil'] = {
|
||||
// Do while/until loop.
|
||||
init: function() {
|
||||
var OPERATORS =
|
||||
[[Blockly.Msg.CONTROLS_WHILEUNTIL_OPERATOR_WHILE, 'WHILE'],
|
||||
[Blockly.Msg.CONTROLS_WHILEUNTIL_OPERATOR_UNTIL, 'UNTIL']];
|
||||
this.setHelpUrl(Blockly.Msg.CONTROLS_WHILEUNTIL_HELPURL);
|
||||
this.setColour(120);
|
||||
this.appendValueInput('BOOL')
|
||||
.setCheck('Boolean')
|
||||
.appendTitle(new Blockly.FieldDropdown(OPERATORS), 'MODE');
|
||||
this.appendStatementInput('DO')
|
||||
.appendTitle(Blockly.Msg.CONTROLS_WHILEUNTIL_INPUT_DO);
|
||||
this.setPreviousStatement(true);
|
||||
this.setNextStatement(true);
|
||||
// Assign 'this' to a variable for use in the tooltip closure below.
|
||||
var thisBlock = this;
|
||||
this.setTooltip(function() {
|
||||
var op = thisBlock.getTitleValue('MODE');
|
||||
var TOOLTIPS = {
|
||||
WHILE: Blockly.Msg.CONTROLS_WHILEUNTIL_TOOLTIP_WHILE,
|
||||
UNTIL: Blockly.Msg.CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL
|
||||
};
|
||||
return TOOLTIPS[op];
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['controls_for'] = {
|
||||
// For loop.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.CONTROLS_FOR_HELPURL);
|
||||
this.setColour(120);
|
||||
this.appendDummyInput()
|
||||
.appendTitle(Blockly.Msg.CONTROLS_FOR_INPUT_WITH)
|
||||
.appendTitle(new Blockly.FieldVariable(null), 'VAR');
|
||||
this.interpolateMsg(Blockly.Msg.CONTROLS_FOR_INPUT_FROM_TO_BY,
|
||||
['FROM', 'Number', Blockly.ALIGN_RIGHT],
|
||||
['TO', 'Number', Blockly.ALIGN_RIGHT],
|
||||
['BY', 'Number', Blockly.ALIGN_RIGHT],
|
||||
Blockly.ALIGN_RIGHT);
|
||||
this.appendStatementInput('DO')
|
||||
.appendTitle(Blockly.Msg.CONTROLS_FOR_INPUT_DO);
|
||||
this.setPreviousStatement(true);
|
||||
this.setNextStatement(true);
|
||||
this.setInputsInline(true);
|
||||
// Assign 'this' to a variable for use in the tooltip closure below.
|
||||
var thisBlock = this;
|
||||
this.setTooltip(function() {
|
||||
return Blockly.Msg.CONTROLS_FOR_TOOLTIP.replace('%1',
|
||||
thisBlock.getTitleValue('VAR'));
|
||||
});
|
||||
},
|
||||
getVars: function() {
|
||||
return [this.getTitleValue('VAR')];
|
||||
},
|
||||
renameVar: function(oldName, newName) {
|
||||
if (Blockly.Names.equals(oldName, this.getTitleValue('VAR'))) {
|
||||
this.setTitleValue(newName, 'VAR');
|
||||
}
|
||||
},
|
||||
customContextMenu: function(options) {
|
||||
var option = {enabled: true};
|
||||
var name = this.getTitleValue('VAR');
|
||||
option.text = Blockly.Msg.VARIABLES_SET_CREATE_GET.replace('%1', name);
|
||||
var xmlTitle = goog.dom.createDom('title', null, name);
|
||||
xmlTitle.setAttribute('name', 'VAR');
|
||||
var xmlBlock = goog.dom.createDom('block', null, xmlTitle);
|
||||
xmlBlock.setAttribute('type', 'variables_get');
|
||||
option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock);
|
||||
options.push(option);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['controls_forEach'] = {
|
||||
// For each loop.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.CONTROLS_FOREACH_HELPURL);
|
||||
this.setColour(120);
|
||||
this.appendValueInput('LIST')
|
||||
.setCheck('Array')
|
||||
.appendTitle(Blockly.Msg.CONTROLS_FOREACH_INPUT_ITEM)
|
||||
.appendTitle(new Blockly.FieldVariable(null), 'VAR')
|
||||
.appendTitle(Blockly.Msg.CONTROLS_FOREACH_INPUT_INLIST);
|
||||
if (Blockly.Msg.CONTROLS_FOREACH_INPUT_INLIST_TAIL) {
|
||||
this.appendDummyInput()
|
||||
.appendTitle(Blockly.Msg.CONTROLS_FOREACH_INPUT_INLIST_TAIL);
|
||||
this.setInputsInline(true);
|
||||
}
|
||||
this.appendStatementInput('DO')
|
||||
.appendTitle(Blockly.Msg.CONTROLS_FOREACH_INPUT_DO);
|
||||
this.setPreviousStatement(true);
|
||||
this.setNextStatement(true);
|
||||
// Assign 'this' to a variable for use in the tooltip closure below.
|
||||
var thisBlock = this;
|
||||
this.setTooltip(function() {
|
||||
return Blockly.Msg.CONTROLS_FOREACH_TOOLTIP.replace('%1',
|
||||
thisBlock.getTitleValue('VAR'));
|
||||
});
|
||||
},
|
||||
getVars: function() {
|
||||
return [this.getTitleValue('VAR')];
|
||||
},
|
||||
renameVar: function(oldName, newName) {
|
||||
if (Blockly.Names.equals(oldName, this.getTitleValue('VAR'))) {
|
||||
this.setTitleValue(newName, 'VAR');
|
||||
}
|
||||
},
|
||||
customContextMenu: Blockly.Blocks['controls_for'].customContextMenu
|
||||
};
|
||||
|
||||
Blockly.Blocks['controls_flow_statements'] = {
|
||||
// Flow statements: continue, break.
|
||||
init: function() {
|
||||
var OPERATORS =
|
||||
[[Blockly.Msg.CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK, 'BREAK'],
|
||||
[Blockly.Msg.CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE, 'CONTINUE']];
|
||||
this.setHelpUrl(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_HELPURL);
|
||||
this.setColour(120);
|
||||
this.appendDummyInput()
|
||||
.appendTitle(new Blockly.FieldDropdown(OPERATORS), 'FLOW');
|
||||
this.setPreviousStatement(true);
|
||||
// Assign 'this' to a variable for use in the tooltip closure below.
|
||||
var thisBlock = this;
|
||||
this.setTooltip(function() {
|
||||
var op = thisBlock.getTitleValue('FLOW');
|
||||
var TOOLTIPS = {
|
||||
BREAK: Blockly.Msg.CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK,
|
||||
CONTINUE: Blockly.Msg.CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE
|
||||
};
|
||||
return thisBlock.TOOLTIPS[op];
|
||||
});
|
||||
},
|
||||
onchange: function() {
|
||||
if (!this.workspace) {
|
||||
// Block has been deleted.
|
||||
return;
|
||||
}
|
||||
var legal = false;
|
||||
// Is the block nested in a control statement?
|
||||
var block = this;
|
||||
do {
|
||||
if (block.type == 'controls_repeat' ||
|
||||
block.type == 'controls_repeat_ext' ||
|
||||
block.type == 'controls_forEach' ||
|
||||
block.type == 'controls_for' ||
|
||||
block.type == 'controls_whileUntil') {
|
||||
legal = true;
|
||||
break;
|
||||
}
|
||||
block = block.getSurroundParent();
|
||||
} while (block);
|
||||
if (legal) {
|
||||
this.setWarningText(null);
|
||||
} else {
|
||||
this.setWarningText(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING);
|
||||
}
|
||||
}
|
||||
};
|
||||
364
blocks/math.js
Normal file
364
blocks/math.js
Normal file
@@ -0,0 +1,364 @@
|
||||
/**
|
||||
* Visual Blocks Editor
|
||||
*
|
||||
* Copyright 2012 Google Inc.
|
||||
* http://blockly.googlecode.com/
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Math blocks for Blockly.
|
||||
* @author q.neutron@gmail.com (Quynh Neutron)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Blocks.math');
|
||||
|
||||
goog.require('Blockly.Blocks');
|
||||
|
||||
|
||||
Blockly.Blocks['math_number'] = {
|
||||
// Numeric value.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.MATH_NUMBER_HELPURL);
|
||||
this.setColour(230);
|
||||
this.appendDummyInput()
|
||||
.appendTitle(new Blockly.FieldTextInput('0',
|
||||
Blockly.FieldTextInput.numberValidator), 'NUM');
|
||||
this.setOutput(true, 'Number');
|
||||
this.setTooltip(Blockly.Msg.MATH_NUMBER_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['math_arithmetic'] = {
|
||||
// Basic arithmetic operator.
|
||||
init: function() {
|
||||
var OPERATORS =
|
||||
[[Blockly.Msg.MATH_ADDITION_SYMBOL, 'ADD'],
|
||||
[Blockly.Msg.MATH_SUBTRACTION_SYMBOL, 'MINUS'],
|
||||
[Blockly.Msg.MATH_MULTIPLICATION_SYMBOL, 'MULTIPLY'],
|
||||
[Blockly.Msg.MATH_DIVISION_SYMBOL, 'DIVIDE'],
|
||||
[Blockly.Msg.MATH_POWER_SYMBOL, 'POWER']];
|
||||
this.setHelpUrl(Blockly.Msg.MATH_ARITHMETIC_HELPURL);
|
||||
this.setColour(230);
|
||||
this.setOutput(true, 'Number');
|
||||
this.appendValueInput('A')
|
||||
.setCheck('Number');
|
||||
this.appendValueInput('B')
|
||||
.setCheck('Number')
|
||||
.appendTitle(new Blockly.FieldDropdown(OPERATORS), 'OP');
|
||||
this.setInputsInline(true);
|
||||
// Assign 'this' to a variable for use in the tooltip closure below.
|
||||
var thisBlock = this;
|
||||
this.setTooltip(function() {
|
||||
var mode = thisBlock.getTitleValue('OP');
|
||||
var TOOLTIPS = {
|
||||
ADD: Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_ADD,
|
||||
MINUS: Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MINUS,
|
||||
MULTIPLY: Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MULTIPLY,
|
||||
DIVIDE: Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_DIVIDE,
|
||||
POWER: Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_POWER
|
||||
};
|
||||
return TOOLTIPS[mode];
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['math_single'] = {
|
||||
// Advanced math operators with single operand.
|
||||
init: function() {
|
||||
var OPERATORS =
|
||||
[[Blockly.Msg.MATH_SINGLE_OP_ROOT, 'ROOT'],
|
||||
[Blockly.Msg.MATH_SINGLE_OP_ABSOLUTE, 'ABS'],
|
||||
['-', 'NEG'],
|
||||
['ln', 'LN'],
|
||||
['log10', 'LOG10'],
|
||||
['e^', 'EXP'],
|
||||
['10^', 'POW10']];
|
||||
this.setHelpUrl(Blockly.Msg.MATH_SINGLE_HELPURL);
|
||||
this.setColour(230);
|
||||
this.setOutput(true, 'Number');
|
||||
this.appendValueInput('NUM')
|
||||
.setCheck('Number')
|
||||
.appendTitle(new Blockly.FieldDropdown(OPERATORS), 'OP');
|
||||
// Assign 'this' to a variable for use in the tooltip closure below.
|
||||
var thisBlock = this;
|
||||
this.setTooltip(function() {
|
||||
var mode = thisBlock.getTitleValue('OP');
|
||||
var TOOLTIPS = {
|
||||
ROOT: Blockly.Msg.MATH_SINGLE_TOOLTIP_ROOT,
|
||||
ABS: Blockly.Msg.MATH_SINGLE_TOOLTIP_ABS,
|
||||
NEG: Blockly.Msg.MATH_SINGLE_TOOLTIP_NEG,
|
||||
LN: Blockly.Msg.MATH_SINGLE_TOOLTIP_LN,
|
||||
LOG10: Blockly.Msg.MATH_SINGLE_TOOLTIP_LOG10,
|
||||
EXP: Blockly.Msg.MATH_SINGLE_TOOLTIP_EXP,
|
||||
POW10: Blockly.Msg.MATH_SINGLE_TOOLTIP_POW10
|
||||
};
|
||||
return TOOLTIPS[mode];
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['math_trig'] = {
|
||||
// Trigonometry operators.
|
||||
init: function() {
|
||||
var OPERATORS =
|
||||
[[Blockly.Msg.MATH_TRIG_SIN, 'SIN'],
|
||||
[Blockly.Msg.MATH_TRIG_COS, 'COS'],
|
||||
[Blockly.Msg.MATH_TRIG_TAN, 'TAN'],
|
||||
[Blockly.Msg.MATH_TRIG_ASIN, 'ASIN'],
|
||||
[Blockly.Msg.MATH_TRIG_ACOS, 'ACOS'],
|
||||
[Blockly.Msg.MATH_TRIG_ATAN, 'ATAN']];
|
||||
this.setHelpUrl(Blockly.Msg.MATH_TRIG_HELPURL);
|
||||
this.setColour(230);
|
||||
this.setOutput(true, 'Number');
|
||||
this.appendValueInput('NUM')
|
||||
.setCheck('Number')
|
||||
.appendTitle(new Blockly.FieldDropdown(OPERATORS), 'OP');
|
||||
// Assign 'this' to a variable for use in the tooltip closure below.
|
||||
var thisBlock = this;
|
||||
this.setTooltip(function() {
|
||||
var mode = thisBlock.getTitleValue('OP');
|
||||
var TOOLTIPS = {
|
||||
SIN: Blockly.Msg.MATH_TRIG_TOOLTIP_SIN,
|
||||
COS: Blockly.Msg.MATH_TRIG_TOOLTIP_COS,
|
||||
TAN: Blockly.Msg.MATH_TRIG_TOOLTIP_TAN,
|
||||
ASIN: Blockly.Msg.MATH_TRIG_TOOLTIP_ASIN,
|
||||
ACOS: Blockly.Msg.MATH_TRIG_TOOLTIP_ACOS,
|
||||
ATAN: Blockly.Msg.MATH_TRIG_TOOLTIP_ATAN
|
||||
};
|
||||
return TOOLTIPS[mode];
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['math_constant'] = {
|
||||
// Constants: PI, E, the Golden Ratio, sqrt(2), 1/sqrt(2), INFINITY.
|
||||
init: function() {
|
||||
var CONSTANTS =
|
||||
[['\u03c0', 'PI'],
|
||||
['e', 'E'],
|
||||
['\u03c6', 'GOLDEN_RATIO'],
|
||||
['sqrt(2)', 'SQRT2'],
|
||||
['sqrt(\u00bd)', 'SQRT1_2'],
|
||||
['\u221e', 'INFINITY']];
|
||||
this.setHelpUrl(Blockly.Msg.MATH_CONSTANT_HELPURL);
|
||||
this.setColour(230);
|
||||
this.setOutput(true, 'Number');
|
||||
this.appendDummyInput()
|
||||
.appendTitle(new Blockly.FieldDropdown(CONSTANTS), 'CONSTANT');
|
||||
this.setTooltip(Blockly.Msg.MATH_CONSTANT_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['math_number_property'] = {
|
||||
// Check if a number is even, odd, prime, whole, positive, or negative
|
||||
// or if it is divisible by certain number. Returns true or false.
|
||||
init: function() {
|
||||
var PROPERTIES =
|
||||
[[Blockly.Msg.MATH_IS_EVEN, 'EVEN'],
|
||||
[Blockly.Msg.MATH_IS_ODD, 'ODD'],
|
||||
[Blockly.Msg.MATH_IS_PRIME, 'PRIME'],
|
||||
[Blockly.Msg.MATH_IS_WHOLE, 'WHOLE'],
|
||||
[Blockly.Msg.MATH_IS_POSITIVE, 'POSITIVE'],
|
||||
[Blockly.Msg.MATH_IS_NEGATIVE, 'NEGATIVE'],
|
||||
[Blockly.Msg.MATH_IS_DIVISIBLE_BY, 'DIVISIBLE_BY']];
|
||||
this.setColour(230);
|
||||
this.appendValueInput('NUMBER_TO_CHECK')
|
||||
.setCheck('Number');
|
||||
var dropdown = new Blockly.FieldDropdown(PROPERTIES, function(option) {
|
||||
var divisorInput = (option == 'DIVISIBLE_BY');
|
||||
this.sourceBlock_.updateShape(divisorInput);
|
||||
});
|
||||
this.appendDummyInput()
|
||||
.appendTitle(dropdown, 'PROPERTY');
|
||||
this.setInputsInline(true);
|
||||
this.setOutput(true, 'Boolean');
|
||||
this.setTooltip(Blockly.Msg.MATH_IS_TOOLTIP);
|
||||
},
|
||||
mutationToDom: function() {
|
||||
// Save whether the 'divisorInput' should be true of false (present or not).
|
||||
var container = document.createElement('mutation');
|
||||
var divisorInput = (this.getTitleValue('PROPERTY') == 'DIVISIBLE_BY');
|
||||
container.setAttribute('divisor_input', divisorInput);
|
||||
return container;
|
||||
},
|
||||
domToMutation: function(xmlElement) {
|
||||
// Restore the 'divisorInput'.
|
||||
var divisorInput = (xmlElement.getAttribute('divisor_input') == 'true');
|
||||
this.updateShape(divisorInput);
|
||||
},
|
||||
updateShape: function(divisorInput) {
|
||||
// Add or remove a Value Input.
|
||||
var inputExists = this.getInput('DIVISOR');
|
||||
if (divisorInput) {
|
||||
if (!inputExists) {
|
||||
this.appendValueInput('DIVISOR')
|
||||
.setCheck('Number');
|
||||
}
|
||||
} else if (inputExists) {
|
||||
this.removeInput('DIVISOR');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['math_change'] = {
|
||||
// Add to a variable in place.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.MATH_CHANGE_HELPURL);
|
||||
this.setColour(230);
|
||||
this.appendValueInput('DELTA')
|
||||
.setCheck('Number')
|
||||
.appendTitle(Blockly.Msg.MATH_CHANGE_TITLE_CHANGE)
|
||||
.appendTitle(new Blockly.FieldVariable(
|
||||
Blockly.Msg.MATH_CHANGE_TITLE_ITEM), 'VAR')
|
||||
.appendTitle(Blockly.Msg.MATH_CHANGE_INPUT_BY);
|
||||
this.setPreviousStatement(true);
|
||||
this.setNextStatement(true);
|
||||
// Assign 'this' to a variable for use in the tooltip closure below.
|
||||
var thisBlock = this;
|
||||
this.setTooltip(function() {
|
||||
return Blockly.Msg.MATH_CHANGE_TOOLTIP.replace('%1',
|
||||
thisBlock.getTitleValue('VAR'));
|
||||
});
|
||||
},
|
||||
getVars: function() {
|
||||
return [this.getTitleValue('VAR')];
|
||||
},
|
||||
renameVar: function(oldName, newName) {
|
||||
if (Blockly.Names.equals(oldName, this.getTitleValue('VAR'))) {
|
||||
this.setTitleValue(newName, 'VAR');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['math_round'] = {
|
||||
// Rounding functions.
|
||||
init: function() {
|
||||
var OPERATORS =
|
||||
[[Blockly.Msg.MATH_ROUND_OPERATOR_ROUND, 'ROUND'],
|
||||
[Blockly.Msg.MATH_ROUND_OPERATOR_ROUNDUP, 'ROUNDUP'],
|
||||
[Blockly.Msg.MATH_ROUND_OPERATOR_ROUNDDOWN, 'ROUNDDOWN']];
|
||||
this.setHelpUrl(Blockly.Msg.MATH_ROUND_HELPURL);
|
||||
this.setColour(230);
|
||||
this.setOutput(true, 'Number');
|
||||
this.appendValueInput('NUM')
|
||||
.setCheck('Number')
|
||||
.appendTitle(new Blockly.FieldDropdown(OPERATORS), 'OP');
|
||||
this.setTooltip(Blockly.Msg.MATH_ROUND_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['math_on_list'] = {
|
||||
// Evaluate a list of numbers to return sum, average, min, max, etc.
|
||||
// Some functions also work on text (min, max, mode, median).
|
||||
init: function() {
|
||||
var OPERATORS =
|
||||
[[Blockly.Msg.MATH_ONLIST_OPERATOR_SUM, 'SUM'],
|
||||
[Blockly.Msg.MATH_ONLIST_OPERATOR_MIN, 'MIN'],
|
||||
[Blockly.Msg.MATH_ONLIST_OPERATOR_MAX, 'MAX'],
|
||||
[Blockly.Msg.MATH_ONLIST_OPERATOR_AVERAGE, 'AVERAGE'],
|
||||
[Blockly.Msg.MATH_ONLIST_OPERATOR_MEDIAN, 'MEDIAN'],
|
||||
[Blockly.Msg.MATH_ONLIST_OPERATOR_MODE, 'MODE'],
|
||||
[Blockly.Msg.MATH_ONLIST_OPERATOR_STD_DEV, 'STD_DEV'],
|
||||
[Blockly.Msg.MATH_ONLIST_OPERATOR_RANDOM, 'RANDOM']];
|
||||
// Assign 'this' to a variable for use in the closure below.
|
||||
var thisBlock = this;
|
||||
this.setHelpUrl(Blockly.Msg.MATH_ONLIST_HELPURL);
|
||||
this.setColour(230);
|
||||
this.setOutput(true, 'Number');
|
||||
var dropdown = new Blockly.FieldDropdown(OPERATORS, function(newOp) {
|
||||
if (newOp == 'MODE') {
|
||||
thisBlock.outputConnection.setCheck('Array');
|
||||
} else {
|
||||
thisBlock.outputConnection.setCheck('Number');
|
||||
}
|
||||
});
|
||||
this.appendValueInput('LIST')
|
||||
.setCheck('Array')
|
||||
.appendTitle(dropdown, 'OP');
|
||||
this.setTooltip(function() {
|
||||
var mode = thisBlock.getTitleValue('OP');
|
||||
var TOOLTIPS = {
|
||||
SUM: Blockly.Msg.MATH_ONLIST_TOOLTIP_SUM,
|
||||
MIN: Blockly.Msg.MATH_ONLIST_TOOLTIP_MIN,
|
||||
MAX: Blockly.Msg.MATH_ONLIST_TOOLTIP_MAX,
|
||||
AVERAGE: Blockly.Msg.MATH_ONLIST_TOOLTIP_AVERAGE,
|
||||
MEDIAN: Blockly.Msg.MATH_ONLIST_TOOLTIP_MEDIAN,
|
||||
MODE: Blockly.Msg.MATH_ONLIST_TOOLTIP_MODE,
|
||||
STD_DEV: Blockly.Msg.MATH_ONLIST_TOOLTIP_STD_DEV,
|
||||
RANDOM: Blockly.Msg.MATH_ONLIST_TOOLTIP_RANDOM
|
||||
};
|
||||
return TOOLTIPS[mode];
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['math_modulo'] = {
|
||||
// Remainder of a division.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.MATH_MODULO_HELPURL);
|
||||
this.setColour(230);
|
||||
this.setOutput(true, 'Number');
|
||||
this.interpolateMsg(Blockly.Msg.MATH_MODULO_TITLE,
|
||||
['DIVIDEND', 'Number', Blockly.ALIGN_RIGHT],
|
||||
['DIVISOR', 'Number', Blockly.ALIGN_RIGHT],
|
||||
Blockly.ALIGN_RIGHT);
|
||||
this.setInputsInline(true);
|
||||
this.setTooltip(Blockly.Msg.MATH_MODULO_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['math_constrain'] = {
|
||||
// Constrain a number between two limits.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.MATH_CONSTRAIN_HELPURL);
|
||||
this.setColour(230);
|
||||
this.setOutput(true, 'Number');
|
||||
this.interpolateMsg(Blockly.Msg.MATH_CONSTRAIN_TITLE,
|
||||
['VALUE', 'Number', Blockly.ALIGN_RIGHT],
|
||||
['LOW', 'Number', Blockly.ALIGN_RIGHT],
|
||||
['HIGH', 'Number', Blockly.ALIGN_RIGHT],
|
||||
Blockly.ALIGN_RIGHT)
|
||||
this.setInputsInline(true);
|
||||
this.setTooltip(Blockly.Msg.MATH_CONSTRAIN_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['math_random_int'] = {
|
||||
// Random integer between [X] and [Y].
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.MATH_RANDOM_INT_HELPURL);
|
||||
this.setColour(230);
|
||||
this.setOutput(true, 'Number');
|
||||
this.interpolateMsg(Blockly.Msg.MATH_RANDOM_INT_TITLE,
|
||||
['FROM', 'Number', Blockly.ALIGN_RIGHT],
|
||||
['TO', 'Number', Blockly.ALIGN_RIGHT],
|
||||
Blockly.ALIGN_RIGHT);
|
||||
this.setInputsInline(true);
|
||||
this.setTooltip(Blockly.Msg.MATH_RANDOM_INT_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['math_random_float'] = {
|
||||
// Random fraction between 0 and 1.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.MATH_RANDOM_FLOAT_HELPURL);
|
||||
this.setColour(230);
|
||||
this.setOutput(true, 'Number');
|
||||
this.appendDummyInput()
|
||||
.appendTitle(Blockly.Msg.MATH_RANDOM_FLOAT_TITLE_RANDOM);
|
||||
this.setTooltip(Blockly.Msg.MATH_RANDOM_FLOAT_TOOLTIP);
|
||||
}
|
||||
};
|
||||
517
blocks/procedures.js
Normal file
517
blocks/procedures.js
Normal file
@@ -0,0 +1,517 @@
|
||||
/**
|
||||
* Visual Blocks Editor
|
||||
*
|
||||
* Copyright 2012 Google Inc.
|
||||
* http://blockly.googlecode.com/
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Procedure blocks for Blockly.
|
||||
* @author fraser@google.com (Neil Fraser)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Blocks.procedures');
|
||||
|
||||
goog.require('Blockly.Blocks');
|
||||
|
||||
|
||||
Blockly.Blocks['procedures_defnoreturn'] = {
|
||||
// Define a procedure with no return value.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.PROCEDURES_DEFNORETURN_HELPURL);
|
||||
this.setColour(290);
|
||||
var name = Blockly.Procedures.findLegalName(
|
||||
Blockly.Msg.PROCEDURES_DEFNORETURN_PROCEDURE, this);
|
||||
this.appendDummyInput()
|
||||
.appendTitle(Blockly.Msg.PROCEDURES_DEFNORETURN_TITLE)
|
||||
.appendTitle(new Blockly.FieldTextInput(name,
|
||||
Blockly.Procedures.rename), 'NAME')
|
||||
.appendTitle('', 'PARAMS');
|
||||
this.appendStatementInput('STACK')
|
||||
.appendTitle(Blockly.Msg.PROCEDURES_DEFNORETURN_DO);
|
||||
this.setMutator(new Blockly.Mutator(['procedures_mutatorarg']));
|
||||
this.setTooltip(Blockly.Msg.PROCEDURES_DEFNORETURN_TOOLTIP);
|
||||
this.arguments_ = [];
|
||||
},
|
||||
updateParams_: function() {
|
||||
// Check for duplicated arguments.
|
||||
var badArg = false;
|
||||
var hash = {};
|
||||
for (var x = 0; x < this.arguments_.length; x++) {
|
||||
if (hash['arg_' + this.arguments_[x].toLowerCase()]) {
|
||||
badArg = true;
|
||||
break;
|
||||
}
|
||||
hash['arg_' + this.arguments_[x].toLowerCase()] = true;
|
||||
}
|
||||
if (badArg) {
|
||||
this.setWarningText(Blockly.Msg.PROCEDURES_DEF_DUPLICATE_WARNING);
|
||||
} else {
|
||||
this.setWarningText(null);
|
||||
}
|
||||
// Merge the arguments into a human-readable list.
|
||||
var paramString = '';
|
||||
if (this.arguments_.length) {
|
||||
paramString = Blockly.Msg.PROCEDURES_BEFORE_PARAMS +
|
||||
' ' + this.arguments_.join(', ');
|
||||
}
|
||||
this.setTitleValue(paramString, 'PARAMS');
|
||||
},
|
||||
mutationToDom: function() {
|
||||
var container = document.createElement('mutation');
|
||||
for (var x = 0; x < this.arguments_.length; x++) {
|
||||
var parameter = document.createElement('arg');
|
||||
parameter.setAttribute('name', this.arguments_[x]);
|
||||
container.appendChild(parameter);
|
||||
}
|
||||
return container;
|
||||
},
|
||||
domToMutation: function(xmlElement) {
|
||||
this.arguments_ = [];
|
||||
for (var x = 0, childNode; childNode = xmlElement.childNodes[x]; x++) {
|
||||
if (childNode.nodeName.toLowerCase() == 'arg') {
|
||||
this.arguments_.push(childNode.getAttribute('name'));
|
||||
}
|
||||
}
|
||||
this.updateParams_();
|
||||
},
|
||||
decompose: function(workspace) {
|
||||
var containerBlock = new Blockly.Block(workspace,
|
||||
'procedures_mutatorcontainer');
|
||||
containerBlock.initSvg();
|
||||
var connection = containerBlock.getInput('STACK').connection;
|
||||
for (var x = 0; x < this.arguments_.length; x++) {
|
||||
var paramBlock = new Blockly.Block(workspace, 'procedures_mutatorarg');
|
||||
paramBlock.initSvg();
|
||||
paramBlock.setTitleValue(this.arguments_[x], 'NAME');
|
||||
// Store the old location.
|
||||
paramBlock.oldLocation = x;
|
||||
connection.connect(paramBlock.previousConnection);
|
||||
connection = paramBlock.nextConnection;
|
||||
}
|
||||
// Initialize procedure's callers with blank IDs.
|
||||
Blockly.Procedures.mutateCallers(this.getTitleValue('NAME'),
|
||||
this.workspace, this.arguments_, null);
|
||||
return containerBlock;
|
||||
},
|
||||
compose: function(containerBlock) {
|
||||
this.arguments_ = [];
|
||||
this.paramIds_ = [];
|
||||
var paramBlock = containerBlock.getInputTargetBlock('STACK');
|
||||
while (paramBlock) {
|
||||
this.arguments_.push(paramBlock.getTitleValue('NAME'));
|
||||
this.paramIds_.push(paramBlock.id);
|
||||
paramBlock = paramBlock.nextConnection &&
|
||||
paramBlock.nextConnection.targetBlock();
|
||||
}
|
||||
this.updateParams_();
|
||||
Blockly.Procedures.mutateCallers(this.getTitleValue('NAME'),
|
||||
this.workspace, this.arguments_, this.paramIds_);
|
||||
},
|
||||
dispose: function() {
|
||||
// Dispose of any callers.
|
||||
var name = this.getTitleValue('NAME');
|
||||
Blockly.Procedures.disposeCallers(name, this.workspace);
|
||||
// Call parent's destructor.
|
||||
Blockly.Block.prototype.dispose.apply(this, arguments);
|
||||
},
|
||||
getProcedureDef: function() {
|
||||
// Return the name of the defined procedure,
|
||||
// a list of all its arguments,
|
||||
// and that it DOES NOT have a return value.
|
||||
return [this.getTitleValue('NAME'), this.arguments_, false];
|
||||
},
|
||||
getVars: function() {
|
||||
return this.arguments_;
|
||||
},
|
||||
renameVar: function(oldName, newName) {
|
||||
var change = false;
|
||||
for (var x = 0; x < this.arguments_.length; x++) {
|
||||
if (Blockly.Names.equals(oldName, this.arguments_[x])) {
|
||||
this.arguments_[x] = newName;
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
if (change) {
|
||||
this.updateParams_();
|
||||
// Update the mutator's variables if the mutator is open.
|
||||
if (this.mutator.isVisible_()) {
|
||||
var blocks = this.mutator.workspace_.getAllBlocks();
|
||||
for (var x = 0, block; block = blocks[x]; x++) {
|
||||
if (block.type == 'procedures_mutatorarg' &&
|
||||
Blockly.Names.equals(oldName, block.getTitleValue('NAME'))) {
|
||||
block.setTitleValue(newName, 'NAME');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
customContextMenu: function(options) {
|
||||
// Add option to create caller.
|
||||
var option = {enabled: true};
|
||||
var name = this.getTitleValue('NAME');
|
||||
option.text = Blockly.Msg.PROCEDURES_CREATE_DO.replace('%1', name);
|
||||
|
||||
var xmlMutation = goog.dom.createDom('mutation');
|
||||
xmlMutation.setAttribute('name', name);
|
||||
for (var x = 0; x < this.arguments_.length; x++) {
|
||||
var xmlArg = goog.dom.createDom('arg');
|
||||
xmlArg.setAttribute('name', this.arguments_[x]);
|
||||
xmlMutation.appendChild(xmlArg);
|
||||
}
|
||||
var xmlBlock = goog.dom.createDom('block', null, xmlMutation);
|
||||
xmlBlock.setAttribute('type', this.callType_);
|
||||
option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock);
|
||||
|
||||
options.push(option);
|
||||
// Add options to create getters for each parameter.
|
||||
for (var x = 0; x < this.arguments_.length; x++) {
|
||||
var option = {enabled: true};
|
||||
var name = this.arguments_[x];
|
||||
option.text = Blockly.Msg.VARIABLES_SET_CREATE_GET.replace('%1', name);
|
||||
var xmlTitle = goog.dom.createDom('title', null, name);
|
||||
xmlTitle.setAttribute('name', 'VAR');
|
||||
var xmlBlock = goog.dom.createDom('block', null, xmlTitle);
|
||||
xmlBlock.setAttribute('type', 'variables_get');
|
||||
option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock);
|
||||
options.push(option);
|
||||
}
|
||||
},
|
||||
callType_: 'procedures_callnoreturn'
|
||||
};
|
||||
|
||||
Blockly.Blocks['procedures_defreturn'] = {
|
||||
// Define a procedure with a return value.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.PROCEDURES_DEFRETURN_HELPURL);
|
||||
this.setColour(290);
|
||||
var name = Blockly.Procedures.findLegalName(
|
||||
Blockly.Msg.PROCEDURES_DEFRETURN_PROCEDURE, this);
|
||||
this.appendDummyInput()
|
||||
.appendTitle(Blockly.Msg.PROCEDURES_DEFRETURN_TITLE)
|
||||
.appendTitle(new Blockly.FieldTextInput(name,
|
||||
Blockly.Procedures.rename), 'NAME')
|
||||
.appendTitle('', 'PARAMS');
|
||||
this.appendStatementInput('STACK')
|
||||
.appendTitle(Blockly.Msg.PROCEDURES_DEFRETURN_DO);
|
||||
this.appendValueInput('RETURN')
|
||||
.setAlign(Blockly.ALIGN_RIGHT)
|
||||
.appendTitle(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN);
|
||||
this.setMutator(new Blockly.Mutator(['procedures_mutatorarg']));
|
||||
this.setTooltip(Blockly.Msg.PROCEDURES_DEFRETURN_TOOLTIP);
|
||||
this.arguments_ = [];
|
||||
},
|
||||
updateParams_: Blockly.Blocks['procedures_defnoreturn'].updateParams_,
|
||||
mutationToDom: Blockly.Blocks['procedures_defnoreturn'].mutationToDom,
|
||||
domToMutation: Blockly.Blocks['procedures_defnoreturn'].domToMutation,
|
||||
decompose: Blockly.Blocks['procedures_defnoreturn'].decompose,
|
||||
compose: Blockly.Blocks['procedures_defnoreturn'].compose,
|
||||
dispose: Blockly.Blocks['procedures_defnoreturn'].dispose,
|
||||
getProcedureDef: function() {
|
||||
// Return the name of the defined procedure,
|
||||
// a list of all its arguments,
|
||||
// and that it DOES have a return value.
|
||||
return [this.getTitleValue('NAME'), this.arguments_, true];
|
||||
},
|
||||
getVars: Blockly.Blocks['procedures_defnoreturn'].getVars,
|
||||
renameVar: Blockly.Blocks['procedures_defnoreturn'].renameVar,
|
||||
customContextMenu: Blockly.Blocks['procedures_defnoreturn'].customContextMenu,
|
||||
callType_: 'procedures_callreturn'
|
||||
};
|
||||
|
||||
Blockly.Blocks['procedures_mutatorcontainer'] = {
|
||||
// Procedure container (for mutator dialog).
|
||||
init: function() {
|
||||
this.setColour(290);
|
||||
this.appendDummyInput()
|
||||
.appendTitle(Blockly.Msg.PROCEDURES_MUTATORCONTAINER_TITLE);
|
||||
this.appendStatementInput('STACK');
|
||||
this.setTooltip('');
|
||||
this.contextMenu = false;
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['procedures_mutatorarg'] = {
|
||||
// Procedure argument (for mutator dialog).
|
||||
init: function() {
|
||||
this.setColour(290);
|
||||
this.appendDummyInput()
|
||||
.appendTitle(Blockly.Msg.PROCEDURES_MUTATORARG_TITLE)
|
||||
.appendTitle(new Blockly.FieldTextInput('x', this.validator), 'NAME');
|
||||
this.setPreviousStatement(true);
|
||||
this.setNextStatement(true);
|
||||
this.setTooltip('');
|
||||
this.contextMenu = false;
|
||||
},
|
||||
validator: function(newVar) {
|
||||
// Merge runs of whitespace. Strip leading and trailing whitespace.
|
||||
// Beyond this, all names are legal.
|
||||
newVar = newVar.replace(/[\s\xa0]+/g, ' ').replace(/^ | $/g, '');
|
||||
return newVar || null;
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['procedures_callnoreturn'] = {
|
||||
// Call a procedure with no return value.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.PROCEDURES_CALLNORETURN_HELPURL);
|
||||
this.setColour(290);
|
||||
this.appendDummyInput()
|
||||
.appendTitle(Blockly.Msg.PROCEDURES_CALLNORETURN_CALL)
|
||||
.appendTitle('', 'NAME');
|
||||
this.setPreviousStatement(true);
|
||||
this.setNextStatement(true);
|
||||
this.setTooltip(Blockly.Msg.PROCEDURES_CALLNORETURN_TOOLTIP);
|
||||
this.arguments_ = [];
|
||||
this.quarkConnections_ = null;
|
||||
this.quarkArguments_ = null;
|
||||
},
|
||||
getProcedureCall: function() {
|
||||
return this.getTitleValue('NAME');
|
||||
},
|
||||
renameProcedure: function(oldName, newName) {
|
||||
if (Blockly.Names.equals(oldName, this.getTitleValue('NAME'))) {
|
||||
this.setTitleValue(newName, 'NAME');
|
||||
this.setTooltip(
|
||||
(this.outputConnection ? Blockly.Msg.PROCEDURES_CALLRETURN_TOOLTIP
|
||||
: Blockly.Msg.PROCEDURES_CALLNORETURN_TOOLTIP)
|
||||
.replace('%1', newName));
|
||||
}
|
||||
},
|
||||
setProcedureParameters: function(paramNames, paramIds) {
|
||||
// Data structures for parameters on each call block:
|
||||
// this.arguments = ['x', 'y']
|
||||
// Existing param names.
|
||||
// paramNames = ['x', 'y', 'z']
|
||||
// New param names.
|
||||
// paramIds = ['piua', 'f8b_', 'oi.o']
|
||||
// IDs of params (consistent for each parameter through the life of a
|
||||
// mutator, regardless of param renaming).
|
||||
// this.quarkConnections_ {piua: null, f8b_: Blockly.Connection}
|
||||
// Look-up of paramIds to connections plugged into the call block.
|
||||
// this.quarkArguments_ = ['piua', 'f8b_']
|
||||
// Existing param IDs.
|
||||
// Note that quarkConnections_ may include IDs that no longer exist, but
|
||||
// which might reappear if a param is reattached in the mutator.
|
||||
if (!paramIds) {
|
||||
// Reset the quarks (a mutator is about to open).
|
||||
this.quarkConnections_ = {};
|
||||
this.quarkArguments_ = null;
|
||||
return;
|
||||
}
|
||||
if (paramIds.length != paramNames.length) {
|
||||
throw 'Error: paramNames and paramIds must be the same length.';
|
||||
}
|
||||
if (!this.quarkArguments_) {
|
||||
// Initialize tracking for this block.
|
||||
this.quarkConnections_ = {};
|
||||
if (paramNames.join('\n') == this.arguments_.join('\n')) {
|
||||
// No change to the parameters, allow quarkConnections_ to be
|
||||
// populated with the existing connections.
|
||||
this.quarkArguments_ = paramIds;
|
||||
} else {
|
||||
this.quarkArguments_ = [];
|
||||
}
|
||||
}
|
||||
// Switch off rendering while the block is rebuilt.
|
||||
var savedRendered = this.rendered;
|
||||
this.rendered = false;
|
||||
// Update the quarkConnections_ with existing connections.
|
||||
for (var x = this.arguments_.length - 1; x >= 0; x--) {
|
||||
var input = this.getInput('ARG' + x);
|
||||
if (input) {
|
||||
var connection = input.connection.targetConnection;
|
||||
this.quarkConnections_[this.quarkArguments_[x]] = connection;
|
||||
// Disconnect all argument blocks and remove all inputs.
|
||||
this.removeInput('ARG' + x);
|
||||
}
|
||||
}
|
||||
// Rebuild the block's arguments.
|
||||
this.arguments_ = [].concat(paramNames);
|
||||
this.quarkArguments_ = paramIds;
|
||||
for (var x = 0; x < this.arguments_.length; x++) {
|
||||
var input = this.appendValueInput('ARG' + x)
|
||||
.setAlign(Blockly.ALIGN_RIGHT)
|
||||
.appendTitle(this.arguments_[x]);
|
||||
if (this.quarkArguments_) {
|
||||
// Reconnect any child blocks.
|
||||
var quarkName = this.quarkArguments_[x];
|
||||
if (quarkName in this.quarkConnections_) {
|
||||
var connection = this.quarkConnections_[quarkName];
|
||||
if (!connection || connection.targetConnection ||
|
||||
connection.sourceBlock_.workspace != this.workspace) {
|
||||
// Block no longer exists or has been attached elsewhere.
|
||||
delete this.quarkConnections_[quarkName];
|
||||
} else {
|
||||
input.connection.connect(connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Restore rendering and show the changes.
|
||||
this.rendered = savedRendered;
|
||||
if (this.rendered) {
|
||||
this.render();
|
||||
}
|
||||
},
|
||||
mutationToDom: function() {
|
||||
// Save the name and arguments (none of which are editable).
|
||||
var container = document.createElement('mutation');
|
||||
container.setAttribute('name', this.getTitleValue('NAME'));
|
||||
for (var x = 0; x < this.arguments_.length; x++) {
|
||||
var parameter = document.createElement('arg');
|
||||
parameter.setAttribute('name', this.arguments_[x]);
|
||||
container.appendChild(parameter);
|
||||
}
|
||||
return container;
|
||||
},
|
||||
domToMutation: function(xmlElement) {
|
||||
// Restore the name and parameters.
|
||||
var name = xmlElement.getAttribute('name');
|
||||
this.setTitleValue(name, 'NAME');
|
||||
this.setTooltip(
|
||||
(this.outputConnection ? Blockly.Msg.PROCEDURES_CALLRETURN_TOOLTIP
|
||||
: Blockly.Msg.PROCEDURES_CALLNORETURN_TOOLTIP).replace('%1', name));
|
||||
var def = Blockly.Procedures.getDefinition(name, this.workspace);
|
||||
if (def && def.mutator.isVisible()) {
|
||||
// Initialize caller with the mutator's IDs.
|
||||
this.setProcedureParameters(def.arguments_, def.paramIds_);
|
||||
} else {
|
||||
this.arguments_ = [];
|
||||
for (var x = 0, childNode; childNode = xmlElement.childNodes[x]; x++) {
|
||||
if (childNode.nodeName.toLowerCase() == 'arg') {
|
||||
this.arguments_.push(childNode.getAttribute('name'));
|
||||
}
|
||||
}
|
||||
// For the second argument (paramIds) use the arguments list as a dummy
|
||||
// list.
|
||||
this.setProcedureParameters(this.arguments_, this.arguments_);
|
||||
}
|
||||
},
|
||||
renameVar: function(oldName, newName) {
|
||||
for (var x = 0; x < this.arguments_.length; x++) {
|
||||
if (Blockly.Names.equals(oldName, this.arguments_[x])) {
|
||||
this.arguments_[x] = newName;
|
||||
this.getInput('ARG' + x).titleRow[0].setText(newName);
|
||||
}
|
||||
}
|
||||
},
|
||||
customContextMenu: function(options) {
|
||||
// Add option to find caller.
|
||||
var option = {enabled: true};
|
||||
option.text = Blockly.Msg.PROCEDURES_HIGHLIGHT_DEF;
|
||||
var name = this.getTitleValue('NAME');
|
||||
var workspace = this.workspace;
|
||||
option.callback = function() {
|
||||
var def = Blockly.Procedures.getDefinition(name, workspace);
|
||||
def && def.select();
|
||||
};
|
||||
options.push(option);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['procedures_callreturn'] = {
|
||||
// Call a procedure with a return value.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.PROCEDURES_CALLRETURN_HELPURL);
|
||||
this.setColour(290);
|
||||
this.appendDummyInput()
|
||||
.appendTitle(Blockly.Msg.PROCEDURES_CALLRETURN_CALL)
|
||||
.appendTitle('', 'NAME');
|
||||
this.setOutput(true);
|
||||
this.setTooltip(Blockly.Msg.PROCEDURES_CALLRETURN_TOOLTIP);
|
||||
this.arguments_ = [];
|
||||
this.quarkConnections_ = null;
|
||||
this.quarkArguments_ = null;
|
||||
},
|
||||
getProcedureCall: Blockly.Blocks['procedures_callnoreturn'].getProcedureCall,
|
||||
renameProcedure: Blockly.Blocks['procedures_callnoreturn'].renameProcedure,
|
||||
setProcedureParameters:
|
||||
Blockly.Blocks['procedures_callnoreturn'].setProcedureParameters,
|
||||
mutationToDom: Blockly.Blocks['procedures_callnoreturn'].mutationToDom,
|
||||
domToMutation: Blockly.Blocks['procedures_callnoreturn'].domToMutation,
|
||||
renameVar: Blockly.Blocks['procedures_callnoreturn'].renameVar,
|
||||
customContextMenu: Blockly.Blocks['procedures_callnoreturn'].customContextMenu
|
||||
};
|
||||
|
||||
Blockly.Blocks['procedures_ifreturn'] = {
|
||||
// Conditionally return value from a procedure.
|
||||
init: function() {
|
||||
this.setHelpUrl('http://c2.com/cgi/wiki?GuardClause');
|
||||
this.setColour(290);
|
||||
this.appendValueInput('CONDITION')
|
||||
.setCheck('Boolean')
|
||||
.appendTitle(Blockly.Msg.CONTROLS_IF_MSG_IF);
|
||||
this.appendValueInput('VALUE')
|
||||
.appendTitle(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN);
|
||||
this.setInputsInline(true);
|
||||
this.setPreviousStatement(true);
|
||||
this.setNextStatement(true);
|
||||
this.setTooltip(Blockly.Msg.PROCEDURES_IFRETURN_TOOLTIP);
|
||||
this.hasReturnValue_ = true;
|
||||
},
|
||||
mutationToDom: function() {
|
||||
// Save whether this block has a return value.
|
||||
var container = document.createElement('mutation');
|
||||
container.setAttribute('value', Number(this.hasReturnValue_));
|
||||
return container;
|
||||
},
|
||||
domToMutation: function(xmlElement) {
|
||||
// Restore whether this block has a return value.
|
||||
var value = xmlElement.getAttribute('value');
|
||||
this.hasReturnValue_ = (value == 1);
|
||||
if (!this.hasReturnValue_) {
|
||||
this.removeInput('VALUE');
|
||||
this.appendDummyInput('VALUE')
|
||||
.appendTitle(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN);
|
||||
}
|
||||
},
|
||||
onchange: function() {
|
||||
if (!this.workspace) {
|
||||
// Block has been deleted.
|
||||
return;
|
||||
}
|
||||
var legal = false;
|
||||
// Is the block nested in a procedure?
|
||||
var block = this;
|
||||
do {
|
||||
if (block.type == 'procedures_defnoreturn' ||
|
||||
block.type == 'procedures_defreturn') {
|
||||
legal = true;
|
||||
break;
|
||||
}
|
||||
block = block.getSurroundParent();
|
||||
} while (block);
|
||||
if (legal) {
|
||||
// If needed, toggle whether this block has a return value.
|
||||
if (block.type == 'procedures_defnoreturn' && this.hasReturnValue_) {
|
||||
this.removeInput('VALUE');
|
||||
this.appendDummyInput('VALUE')
|
||||
.appendTitle(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN);
|
||||
this.hasReturnValue_ = false;
|
||||
} else if (block.type == 'procedures_defreturn' &&
|
||||
!this.hasReturnValue_) {
|
||||
this.removeInput('VALUE');
|
||||
this.appendValueInput('VALUE')
|
||||
.appendTitle(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN);
|
||||
this.hasReturnValue_ = true;
|
||||
}
|
||||
this.setWarningText(null);
|
||||
} else {
|
||||
this.setWarningText(Blockly.Msg.PROCEDURES_IFRETURN_WARNING);
|
||||
}
|
||||
}
|
||||
};
|
||||
484
blocks/text.js
Normal file
484
blocks/text.js
Normal file
@@ -0,0 +1,484 @@
|
||||
/**
|
||||
* Visual Blocks Editor
|
||||
*
|
||||
* Copyright 2012 Google Inc.
|
||||
* http://blockly.googlecode.com/
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Text blocks for Blockly.
|
||||
* @author fraser@google.com (Neil Fraser)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Blocks.text');
|
||||
|
||||
goog.require('Blockly.Blocks');
|
||||
|
||||
|
||||
Blockly.Blocks['text'] = {
|
||||
// Text value.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.TEXT_TEXT_HELPURL);
|
||||
this.setColour(160);
|
||||
this.appendDummyInput()
|
||||
.appendTitle(new Blockly.FieldImage(Blockly.pathToBlockly +
|
||||
'media/quote0.png', 12, 12))
|
||||
.appendTitle(new Blockly.FieldTextInput(''), 'TEXT')
|
||||
.appendTitle(new Blockly.FieldImage(Blockly.pathToBlockly +
|
||||
'media/quote1.png', 12, 12));
|
||||
this.setOutput(true, 'String');
|
||||
this.setTooltip(Blockly.Msg.TEXT_TEXT_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['text_join'] = {
|
||||
// Create a string made up of any number of elements of any type.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.TEXT_JOIN_HELPURL);
|
||||
this.setColour(160);
|
||||
this.appendValueInput('ADD0')
|
||||
.appendTitle(Blockly.Msg.TEXT_JOIN_TITLE_CREATEWITH);
|
||||
this.appendValueInput('ADD1');
|
||||
this.setOutput(true, 'String');
|
||||
this.setMutator(new Blockly.Mutator(['text_create_join_item']));
|
||||
this.setTooltip(Blockly.Msg.TEXT_JOIN_TOOLTIP);
|
||||
this.itemCount_ = 2;
|
||||
},
|
||||
mutationToDom: function() {
|
||||
var container = document.createElement('mutation');
|
||||
container.setAttribute('items', this.itemCount_);
|
||||
return container;
|
||||
},
|
||||
domToMutation: function(xmlElement) {
|
||||
for (var x = 0; x < this.itemCount_; x++) {
|
||||
this.removeInput('ADD' + x);
|
||||
}
|
||||
this.itemCount_ = parseInt(xmlElement.getAttribute('items'), 10);
|
||||
for (var x = 0; x < this.itemCount_; x++) {
|
||||
var input = this.appendValueInput('ADD' + x);
|
||||
if (x == 0) {
|
||||
input.appendTitle(Blockly.Msg.TEXT_JOIN_TITLE_CREATEWITH);
|
||||
}
|
||||
}
|
||||
if (this.itemCount_ == 0) {
|
||||
this.appendDummyInput('EMPTY')
|
||||
.appendTitle(new Blockly.FieldImage(Blockly.pathToBlockly +
|
||||
'media/quote0.png', 12, 12))
|
||||
.appendTitle(new Blockly.FieldImage(Blockly.pathToBlockly +
|
||||
'media/quote1.png', 12, 12));
|
||||
}
|
||||
},
|
||||
decompose: function(workspace) {
|
||||
var containerBlock = new Blockly.Block(workspace,
|
||||
'text_create_join_container');
|
||||
containerBlock.initSvg();
|
||||
var connection = containerBlock.getInput('STACK').connection;
|
||||
for (var x = 0; x < this.itemCount_; x++) {
|
||||
var itemBlock = new Blockly.Block(workspace, 'text_create_join_item');
|
||||
itemBlock.initSvg();
|
||||
connection.connect(itemBlock.previousConnection);
|
||||
connection = itemBlock.nextConnection;
|
||||
}
|
||||
return containerBlock;
|
||||
},
|
||||
compose: function(containerBlock) {
|
||||
// Disconnect all input blocks and remove all inputs.
|
||||
if (this.itemCount_ == 0) {
|
||||
this.removeInput('EMPTY');
|
||||
} else {
|
||||
for (var x = this.itemCount_ - 1; x >= 0; x--) {
|
||||
this.removeInput('ADD' + x);
|
||||
}
|
||||
}
|
||||
this.itemCount_ = 0;
|
||||
// Rebuild the block's inputs.
|
||||
var itemBlock = containerBlock.getInputTargetBlock('STACK');
|
||||
while (itemBlock) {
|
||||
var input = this.appendValueInput('ADD' + this.itemCount_);
|
||||
if (this.itemCount_ == 0) {
|
||||
input.appendTitle(Blockly.Msg.TEXT_JOIN_TITLE_CREATEWITH);
|
||||
}
|
||||
// Reconnect any child blocks.
|
||||
if (itemBlock.valueConnection_) {
|
||||
input.connection.connect(itemBlock.valueConnection_);
|
||||
}
|
||||
this.itemCount_++;
|
||||
itemBlock = itemBlock.nextConnection &&
|
||||
itemBlock.nextConnection.targetBlock();
|
||||
}
|
||||
if (this.itemCount_ == 0) {
|
||||
this.appendDummyInput('EMPTY')
|
||||
.appendTitle(new Blockly.FieldImage(Blockly.pathToBlockly +
|
||||
'media/quote0.png', 12, 12))
|
||||
.appendTitle(new Blockly.FieldImage(Blockly.pathToBlockly +
|
||||
'media/quote1.png', 12, 12));
|
||||
}
|
||||
},
|
||||
saveConnections: function(containerBlock) {
|
||||
// Store a pointer to any connected child blocks.
|
||||
var itemBlock = containerBlock.getInputTargetBlock('STACK');
|
||||
var x = 0;
|
||||
while (itemBlock) {
|
||||
var input = this.getInput('ADD' + x);
|
||||
itemBlock.valueConnection_ = input && input.connection.targetConnection;
|
||||
x++;
|
||||
itemBlock = itemBlock.nextConnection &&
|
||||
itemBlock.nextConnection.targetBlock();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['text_create_join_container'] = {
|
||||
// Container.
|
||||
init: function() {
|
||||
this.setColour(160);
|
||||
this.appendDummyInput()
|
||||
.appendTitle(Blockly.Msg.TEXT_CREATE_JOIN_TITLE_JOIN);
|
||||
this.appendStatementInput('STACK');
|
||||
this.setTooltip(Blockly.Msg.TEXT_CREATE_JOIN_TOOLTIP);
|
||||
this.contextMenu = false;
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['text_create_join_item'] = {
|
||||
// Add items.
|
||||
init: function() {
|
||||
this.setColour(160);
|
||||
this.appendDummyInput()
|
||||
.appendTitle(Blockly.Msg.TEXT_CREATE_JOIN_ITEM_TITLE_ITEM);
|
||||
this.setPreviousStatement(true);
|
||||
this.setNextStatement(true);
|
||||
this.setTooltip(Blockly.Msg.TEXT_CREATE_JOIN_ITEM_TOOLTIP);
|
||||
this.contextMenu = false;
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['text_append'] = {
|
||||
// Append to a variable in place.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.TEXT_APPEND_HELPURL);
|
||||
this.setColour(160);
|
||||
this.appendValueInput('TEXT')
|
||||
.appendTitle(Blockly.Msg.TEXT_APPEND_TO)
|
||||
.appendTitle(new Blockly.FieldVariable(
|
||||
Blockly.Msg.TEXT_APPEND_VARIABLE), 'VAR')
|
||||
.appendTitle(Blockly.Msg.TEXT_APPEND_APPENDTEXT);
|
||||
this.setPreviousStatement(true);
|
||||
this.setNextStatement(true);
|
||||
// Assign 'this' to a variable for use in the tooltip closure below.
|
||||
var thisBlock = this;
|
||||
this.setTooltip(function() {
|
||||
return Blockly.Msg.TEXT_APPEND_TOOLTIP.replace('%1',
|
||||
thisBlock.getTitleValue('VAR'));
|
||||
});
|
||||
},
|
||||
getVars: function() {
|
||||
return [this.getTitleValue('VAR')];
|
||||
},
|
||||
renameVar: function(oldName, newName) {
|
||||
if (Blockly.Names.equals(oldName, this.getTitleValue('VAR'))) {
|
||||
this.setTitleValue(newName, 'VAR');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['text_length'] = {
|
||||
// String length.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.TEXT_LENGTH_HELPURL);
|
||||
this.setColour(160);
|
||||
this.interpolateMsg(Blockly.Msg.TEXT_LENGTH_TITLE,
|
||||
['VALUE', ['String', 'Array'], Blockly.ALIGN_RIGHT],
|
||||
Blockly.ALIGN_RIGHT);
|
||||
this.setOutput(true, 'Number');
|
||||
this.setTooltip(Blockly.Msg.TEXT_LENGTH_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['text_isEmpty'] = {
|
||||
// Is the string null?
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.TEXT_ISEMPTY_HELPURL);
|
||||
this.setColour(160);
|
||||
this.interpolateMsg(Blockly.Msg.TEXT_ISEMPTY_TITLE,
|
||||
['VALUE', ['String', 'Array'], Blockly.ALIGN_RIGHT],
|
||||
Blockly.ALIGN_RIGHT);
|
||||
this.setOutput(true, 'Boolean');
|
||||
this.setTooltip(Blockly.Msg.TEXT_ISEMPTY_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['text_indexOf'] = {
|
||||
// Find a substring in the text.
|
||||
init: function() {
|
||||
var OPERATORS =
|
||||
[[Blockly.Msg.TEXT_INDEXOF_OPERATOR_FIRST, 'FIRST'],
|
||||
[Blockly.Msg.TEXT_INDEXOF_OPERATOR_LAST, 'LAST']];
|
||||
this.setHelpUrl(Blockly.Msg.TEXT_INDEXOF_HELPURL);
|
||||
this.setColour(160);
|
||||
this.setOutput(true, 'Number');
|
||||
this.appendValueInput('VALUE')
|
||||
.setCheck('String')
|
||||
.appendTitle(Blockly.Msg.TEXT_INDEXOF_INPUT_INTEXT);
|
||||
this.appendValueInput('FIND')
|
||||
.setCheck('String')
|
||||
.appendTitle(new Blockly.FieldDropdown(OPERATORS), 'END');
|
||||
if (Blockly.Msg.TEXT_INDEXOF_TAIL) {
|
||||
this.appendDummyInput().appendTitle(Blockly.Msg.TEXT_INDEXOF_TAIL);
|
||||
}
|
||||
this.setInputsInline(true);
|
||||
this.setTooltip(Blockly.Msg.TEXT_INDEXOF_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['text_charAt'] = {
|
||||
// Get a character from the string.
|
||||
init: function() {
|
||||
this.WHERE_OPTIONS =
|
||||
[[Blockly.Msg.TEXT_CHARAT_FROM_START, 'FROM_START'],
|
||||
[Blockly.Msg.TEXT_CHARAT_FROM_END, 'FROM_END'],
|
||||
[Blockly.Msg.TEXT_CHARAT_FIRST, 'FIRST'],
|
||||
[Blockly.Msg.TEXT_CHARAT_LAST, 'LAST'],
|
||||
[Blockly.Msg.TEXT_CHARAT_RANDOM, 'RANDOM']];
|
||||
this.setHelpUrl(Blockly.Msg.TEXT_CHARAT_HELPURL);
|
||||
this.setColour(160);
|
||||
this.setOutput(true, 'String');
|
||||
this.appendValueInput('VALUE')
|
||||
.setCheck('String')
|
||||
.appendTitle(Blockly.Msg.TEXT_CHARAT_INPUT_INTEXT);
|
||||
this.appendDummyInput('AT');
|
||||
this.setInputsInline(true);
|
||||
this.updateAt(true);
|
||||
this.setTooltip(Blockly.Msg.TEXT_CHARAT_TOOLTIP);
|
||||
},
|
||||
mutationToDom: function() {
|
||||
// Save whether there is an 'AT' input.
|
||||
var container = document.createElement('mutation');
|
||||
var isAt = this.getInput('AT').type == Blockly.INPUT_VALUE;
|
||||
container.setAttribute('at', isAt);
|
||||
return container;
|
||||
},
|
||||
domToMutation: function(xmlElement) {
|
||||
// Restore the 'AT' input.
|
||||
// Note: Until January 2013 this block did not have mutations,
|
||||
// so 'at' defaults to true.
|
||||
var isAt = (xmlElement.getAttribute('at') != 'false');
|
||||
this.updateAt(isAt);
|
||||
},
|
||||
updateAt: function(isAt) {
|
||||
// Create or delete an input for the numeric index.
|
||||
// Destroy old 'AT' and 'ORDINAL' inputs.
|
||||
this.removeInput('AT');
|
||||
this.removeInput('ORDINAL', true);
|
||||
// Create either a value 'AT' input or a dummy input.
|
||||
if (isAt) {
|
||||
this.appendValueInput('AT').setCheck('Number');
|
||||
if (Blockly.Msg.ORDINAL_NUMBER_SUFFIX) {
|
||||
this.appendDummyInput('ORDINAL')
|
||||
.appendTitle(Blockly.Msg.ORDINAL_NUMBER_SUFFIX);
|
||||
}
|
||||
} else {
|
||||
this.appendDummyInput('AT');
|
||||
}
|
||||
if (Blockly.Msg.TEXT_CHARAT_TAIL) {
|
||||
this.removeInput('TAIL', true);
|
||||
this.appendDummyInput('TAIL')
|
||||
.appendTitle(Blockly.Msg.TEXT_CHARAT_TAIL);
|
||||
}
|
||||
var menu = new Blockly.FieldDropdown(this.WHERE_OPTIONS, function(value) {
|
||||
var newAt = (value == 'FROM_START') || (value == 'FROM_END');
|
||||
// The 'isAt' variable is available due to this function being a closure.
|
||||
if (newAt != isAt) {
|
||||
var block = this.sourceBlock_;
|
||||
block.updateAt(newAt);
|
||||
// This menu has been destroyed and replaced. Update the replacement.
|
||||
block.setTitleValue(value, 'WHERE');
|
||||
return null;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
this.getInput('AT').appendTitle(menu, 'WHERE');
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['text_getSubstring'] = {
|
||||
// Get substring.
|
||||
init: function() {
|
||||
this.WHERE_OPTIONS_1 =
|
||||
[[Blockly.Msg.TEXT_GET_SUBSTRING_START_FROM_START, 'FROM_START'],
|
||||
[Blockly.Msg.TEXT_GET_SUBSTRING_START_FROM_END, 'FROM_END'],
|
||||
[Blockly.Msg.TEXT_GET_SUBSTRING_START_FIRST, 'FIRST']];
|
||||
this.WHERE_OPTIONS_2 =
|
||||
[[Blockly.Msg.TEXT_GET_SUBSTRING_END_FROM_START, 'FROM_START'],
|
||||
[Blockly.Msg.TEXT_GET_SUBSTRING_END_FROM_END, 'FROM_END'],
|
||||
[Blockly.Msg.TEXT_GET_SUBSTRING_END_LAST, 'LAST']];
|
||||
this.setHelpUrl(Blockly.Msg.TEXT_GET_SUBSTRING_HELPURL);
|
||||
this.setColour(160);
|
||||
this.appendValueInput('STRING')
|
||||
.setCheck('String')
|
||||
.appendTitle(Blockly.Msg.TEXT_GET_SUBSTRING_INPUT_IN_TEXT);
|
||||
this.appendDummyInput('AT1');
|
||||
this.appendDummyInput('AT2');
|
||||
if (Blockly.Msg.TEXT_GET_SUBSTRING_TAIL) {
|
||||
this.appendDummyInput('TAIL')
|
||||
.appendTitle(Blockly.Msg.TEXT_GET_SUBSTRING_TAIL);
|
||||
}
|
||||
this.setInputsInline(true);
|
||||
this.setOutput(true, 'String');
|
||||
this.updateAt(1, true);
|
||||
this.updateAt(2, true);
|
||||
this.setTooltip(Blockly.Msg.TEXT_GET_SUBSTRING_TOOLTIP);
|
||||
},
|
||||
mutationToDom: function() {
|
||||
// Save whether there are 'AT' inputs.
|
||||
var container = document.createElement('mutation');
|
||||
var isAt1 = this.getInput('AT1').type == Blockly.INPUT_VALUE;
|
||||
container.setAttribute('at1', isAt1);
|
||||
var isAt2 = this.getInput('AT2').type == Blockly.INPUT_VALUE;
|
||||
container.setAttribute('at2', isAt2);
|
||||
return container;
|
||||
},
|
||||
domToMutation: function(xmlElement) {
|
||||
// Restore the block shape.
|
||||
var isAt1 = (xmlElement.getAttribute('at1') == 'true');
|
||||
var isAt2 = (xmlElement.getAttribute('at2') == 'true');
|
||||
this.updateAt(1, isAt1);
|
||||
this.updateAt(2, isAt2);
|
||||
},
|
||||
updateAt: function(n, isAt) {
|
||||
// Create or delete an input for the numeric index.
|
||||
// Destroy old 'AT' and 'ORDINAL' inputs.
|
||||
this.removeInput('AT' + n);
|
||||
this.removeInput('ORDINAL' + n, true);
|
||||
// Create either a value 'AT' input or a dummy input.
|
||||
if (isAt) {
|
||||
this.appendValueInput('AT' + n).setCheck('Number');
|
||||
if (Blockly.Msg.ORDINAL_NUMBER_SUFFIX) {
|
||||
this.appendDummyInput('ORDINAL' + n)
|
||||
.appendTitle(Blockly.Msg.ORDINAL_NUMBER_SUFFIX);
|
||||
}
|
||||
} else {
|
||||
this.appendDummyInput('AT' + n);
|
||||
}
|
||||
// Move tail, if present, to end of block.
|
||||
if (n == 2 && Blockly.Msg.TEXT_GET_SUBSTRING_TAIL) {
|
||||
this.removeInput('TAIL', true);
|
||||
this.appendDummyInput('TAIL')
|
||||
.appendTitle(Blockly.Msg.TEXT_GET_SUBSTRING_TAIL);
|
||||
}
|
||||
var menu = new Blockly.FieldDropdown(this['WHERE_OPTIONS_' + n],
|
||||
function(value) {
|
||||
var newAt = (value == 'FROM_START') || (value == 'FROM_END');
|
||||
// The 'isAt' variable is available due to this function being a closure.
|
||||
if (newAt != isAt) {
|
||||
var block = this.sourceBlock_;
|
||||
block.updateAt(n, newAt);
|
||||
// This menu has been destroyed and replaced. Update the replacement.
|
||||
block.setTitleValue(value, 'WHERE' + n);
|
||||
return null;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
this.getInput('AT' + n)
|
||||
.appendTitle(menu, 'WHERE' + n);
|
||||
if (n == 1) {
|
||||
this.moveInputBefore('AT1', 'AT2');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['text_changeCase'] = {
|
||||
// Change capitalization.
|
||||
init: function() {
|
||||
var OPERATORS =
|
||||
[[Blockly.Msg.TEXT_CHANGECASE_OPERATOR_UPPERCASE, 'UPPERCASE'],
|
||||
[Blockly.Msg.TEXT_CHANGECASE_OPERATOR_LOWERCASE, 'LOWERCASE'],
|
||||
[Blockly.Msg.TEXT_CHANGECASE_OPERATOR_TITLECASE, 'TITLECASE']];
|
||||
this.setHelpUrl(Blockly.Msg.TEXT_CHANGECASE_HELPURL);
|
||||
this.setColour(160);
|
||||
this.appendValueInput('TEXT')
|
||||
.setCheck('String')
|
||||
.appendTitle(new Blockly.FieldDropdown(OPERATORS), 'CASE');
|
||||
this.setOutput(true, 'String');
|
||||
this.setTooltip(Blockly.Msg.TEXT_CHANGECASE_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['text_trim'] = {
|
||||
// Trim spaces.
|
||||
init: function() {
|
||||
var OPERATORS =
|
||||
[[Blockly.Msg.TEXT_TRIM_OPERATOR_BOTH, 'BOTH'],
|
||||
[Blockly.Msg.TEXT_TRIM_OPERATOR_LEFT, 'LEFT'],
|
||||
[Blockly.Msg.TEXT_TRIM_OPERATOR_RIGHT, 'RIGHT']];
|
||||
this.setHelpUrl(Blockly.Msg.TEXT_TRIM_HELPURL);
|
||||
this.setColour(160);
|
||||
this.appendValueInput('TEXT')
|
||||
.setCheck('String')
|
||||
.appendTitle(new Blockly.FieldDropdown(OPERATORS), 'MODE');
|
||||
this.setOutput(true, 'String');
|
||||
this.setTooltip(Blockly.Msg.TEXT_TRIM_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['text_print'] = {
|
||||
// Print statement.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.TEXT_PRINT_HELPURL);
|
||||
this.setColour(160);
|
||||
this.interpolateMsg(Blockly.Msg.TEXT_PRINT_TITLE,
|
||||
['TEXT', null, Blockly.ALIGN_RIGHT],
|
||||
Blockly.ALIGN_RIGHT);
|
||||
this.setPreviousStatement(true);
|
||||
this.setNextStatement(true);
|
||||
this.setTooltip(Blockly.Msg.TEXT_PRINT_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['text_prompt'] = {
|
||||
// Prompt function.
|
||||
init: function() {
|
||||
var TYPES =
|
||||
[[Blockly.Msg.TEXT_PROMPT_TYPE_TEXT, 'TEXT'],
|
||||
[Blockly.Msg.TEXT_PROMPT_TYPE_NUMBER, 'NUMBER']];
|
||||
// Assign 'this' to a variable for use in the closure below.
|
||||
var thisBlock = this;
|
||||
this.setHelpUrl(Blockly.Msg.TEXT_PROMPT_HELPURL);
|
||||
this.setColour(160);
|
||||
var dropdown = new Blockly.FieldDropdown(TYPES, function(newOp) {
|
||||
if (newOp == 'NUMBER') {
|
||||
thisBlock.outputConnection.setCheck('Number');
|
||||
} else {
|
||||
thisBlock.outputConnection.setCheck('String');
|
||||
}
|
||||
});
|
||||
this.appendDummyInput()
|
||||
.appendTitle(dropdown, 'TYPE')
|
||||
.appendTitle(new Blockly.FieldImage(Blockly.pathToBlockly +
|
||||
'media/quote0.png', 12, 12))
|
||||
.appendTitle(new Blockly.FieldTextInput(''), 'TEXT')
|
||||
.appendTitle(new Blockly.FieldImage(Blockly.pathToBlockly +
|
||||
'media/quote1.png', 12, 12));
|
||||
this.setOutput(true, 'String');
|
||||
// Assign 'this' to a variable for use in the tooltip closure below.
|
||||
var thisBlock = this;
|
||||
this.setTooltip(function() {
|
||||
return (thisBlock.getTitleValue('TYPE') == 'TEXT') ?
|
||||
Blockly.Msg.TEXT_PROMPT_TOOLTIP_TEXT :
|
||||
Blockly.Msg.TEXT_PROMPT_TOOLTIP_NUMBER;
|
||||
});
|
||||
}
|
||||
};
|
||||
92
blocks/variables.js
Normal file
92
blocks/variables.js
Normal file
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Visual Blocks Editor
|
||||
*
|
||||
* Copyright 2012 Google Inc.
|
||||
* http://blockly.googlecode.com/
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Variable blocks for Blockly.
|
||||
* @author fraser@google.com (Neil Fraser)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Blocks.variables');
|
||||
|
||||
goog.require('Blockly.Blocks');
|
||||
|
||||
|
||||
Blockly.Blocks['variables_get'] = {
|
||||
// Variable getter.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.VARIABLES_GET_HELPURL);
|
||||
this.setColour(330);
|
||||
this.appendDummyInput()
|
||||
.appendTitle(Blockly.Msg.VARIABLES_GET_TITLE)
|
||||
.appendTitle(new Blockly.FieldVariable(
|
||||
Blockly.Msg.VARIABLES_GET_ITEM), 'VAR')
|
||||
.appendTitle(Blockly.Msg.VARIABLES_GET_TAIL);
|
||||
this.setOutput(true);
|
||||
this.setTooltip(Blockly.Msg.VARIABLES_GET_TOOLTIP);
|
||||
this.contextMenuMsg_ = Blockly.Msg.VARIABLES_GET_CREATE_SET;
|
||||
this.contextMenuType_ = 'variables_set';
|
||||
},
|
||||
getVars: function() {
|
||||
return [this.getTitleValue('VAR')];
|
||||
},
|
||||
renameVar: function(oldName, newName) {
|
||||
if (Blockly.Names.equals(oldName, this.getTitleValue('VAR'))) {
|
||||
this.setTitleValue(newName, 'VAR');
|
||||
}
|
||||
},
|
||||
customContextMenu: function(options) {
|
||||
var option = {enabled: true};
|
||||
var name = this.getTitleValue('VAR');
|
||||
option.text = this.contextMenuMsg_.replace('%1', name);
|
||||
var xmlTitle = goog.dom.createDom('title', null, name);
|
||||
xmlTitle.setAttribute('name', 'VAR');
|
||||
var xmlBlock = goog.dom.createDom('block', null, xmlTitle);
|
||||
xmlBlock.setAttribute('type', this.contextMenuType_);
|
||||
option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock);
|
||||
options.push(option);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['variables_set'] = {
|
||||
// Variable setter.
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.VARIABLES_SET_HELPURL);
|
||||
this.setColour(330);
|
||||
this.appendValueInput('VALUE')
|
||||
.appendTitle(Blockly.Msg.VARIABLES_SET_TITLE)
|
||||
.appendTitle(new Blockly.FieldVariable(
|
||||
Blockly.Msg.VARIABLES_SET_ITEM), 'VAR')
|
||||
.appendTitle(Blockly.Msg.VARIABLES_SET_TAIL);
|
||||
this.setPreviousStatement(true);
|
||||
this.setNextStatement(true);
|
||||
this.setTooltip(Blockly.Msg.VARIABLES_SET_TOOLTIP);
|
||||
this.contextMenuMsg_ = Blockly.Msg.VARIABLES_SET_CREATE_GET;
|
||||
this.contextMenuType_ = 'variables_get';
|
||||
},
|
||||
getVars: function() {
|
||||
return [this.getTitleValue('VAR')];
|
||||
},
|
||||
renameVar: function(oldName, newName) {
|
||||
if (Blockly.Names.equals(oldName, this.getTitleValue('VAR'))) {
|
||||
this.setTitleValue(newName, 'VAR');
|
||||
}
|
||||
},
|
||||
customContextMenu: Blockly.Blocks['variables_get'].customContextMenu
|
||||
};
|
||||
Reference in New Issue
Block a user