Files
blockly/blocks/logic.js
2014-01-04 03:00:02 -08:00

351 lines
11 KiB
JavaScript

/**
* 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')
.appendField(Blockly.Msg.CONTROLS_IF_MSG_IF);
this.appendStatementInput('DO0')
.appendField(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')
.appendField(Blockly.Msg.CONTROLS_IF_MSG_ELSEIF);
this.appendStatementInput('DO' + x)
.appendField(Blockly.Msg.CONTROLS_IF_MSG_THEN);
}
if (this.elseCount_) {
this.appendStatementInput('ELSE')
.appendField(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')
.appendField(Blockly.Msg.CONTROLS_IF_MSG_ELSEIF);
var doInput = this.appendStatementInput('DO' + this.elseifCount_);
doInput.appendField(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.appendField(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()
.appendField(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()
.appendField(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()
.appendField(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')
.appendField(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.getFieldValue('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')
.appendField(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.getFieldValue('OP');
var TOOLTIPS = {
AND: Blockly.Msg.LOGIC_OPERATION_TOOLTIP_AND,
OR: Blockly.Msg.LOGIC_OPERATION_TOOLTIP_OR
};
return 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()
.appendField(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()
.appendField(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')
.appendField(Blockly.Msg.LOGIC_TERNARY_CONDITION);
this.appendValueInput('THEN')
.appendField(Blockly.Msg.LOGIC_TERNARY_IF_TRUE);
this.appendValueInput('ELSE')
.appendField(Blockly.Msg.LOGIC_TERNARY_IF_FALSE);
this.setOutput(true);
this.setTooltip(Blockly.Msg.LOGIC_TERNARY_TOOLTIP);
}
};