Update to latest version.

This commit is contained in:
Neil Fraser
2014-09-08 14:26:52 -07:00
parent 58f264f4ce
commit d998a1c8ec
737 changed files with 29546 additions and 27625 deletions

View File

@@ -30,7 +30,10 @@ goog.require('Blockly.Blocks');
Blockly.Blocks['procedures_defnoreturn'] = {
// Define a procedure with no return value.
/**
* Block for defining a procedure with no return value.
* @this Blockly.Block
*/
init: function() {
this.setHelpUrl(Blockly.Msg.PROCEDURES_DEFNORETURN_HELPURL);
this.setColour(290);
@@ -41,12 +44,38 @@ Blockly.Blocks['procedures_defnoreturn'] = {
.appendField(new Blockly.FieldTextInput(name,
Blockly.Procedures.rename), 'NAME')
.appendField('', 'PARAMS');
this.appendStatementInput('STACK')
.appendField(Blockly.Msg.PROCEDURES_DEFNORETURN_DO);
this.setMutator(new Blockly.Mutator(['procedures_mutatorarg']));
this.setTooltip(Blockly.Msg.PROCEDURES_DEFNORETURN_TOOLTIP);
this.arguments_ = [];
this.setStatements_(true);
this.statementConnection_ = null;
},
/**
* Add or remove the statement block from this function definition.
* @param {boolean} hasStatements True if a statement block is needed.
* @this Blockly.Block
*/
setStatements_: function(hasStatements) {
if (this.hasStatements_ === hasStatements) {
return;
}
if (hasStatements) {
this.appendStatementInput('STACK')
.appendField(Blockly.Msg.PROCEDURES_DEFNORETURN_DO);
if (this.getInput('RETURN')) {
this.moveInputBefore('STACK', 'RETURN');
}
} else {
this.removeInput('STACK', true);
}
this.hasStatements_ = hasStatements;
},
/**
* Update the display of parameters for this procedure definition block.
* Display a warning if there are duplicately named parameters.
* @private
* @this Blockly.Block
*/
updateParams_: function() {
// Check for duplicated arguments.
var badArg = false;
@@ -71,6 +100,11 @@ Blockly.Blocks['procedures_defnoreturn'] = {
}
this.setFieldValue(paramString, 'PARAMS');
},
/**
* Create XML to represent the argument inputs.
* @return {Element} XML storage element.
* @this Blockly.Block
*/
mutationToDom: function() {
var container = document.createElement('mutation');
for (var x = 0; x < this.arguments_.length; x++) {
@@ -78,8 +112,18 @@ Blockly.Blocks['procedures_defnoreturn'] = {
parameter.setAttribute('name', this.arguments_[x]);
container.appendChild(parameter);
}
// Save whether the statement input is visible.
if (!this.hasStatements_) {
container.setAttribute('statements', 'false');
}
return container;
},
/**
* Parse XML to restore the argument inputs.
* @param {!Element} xmlElement XML storage element.
* @this Blockly.Block
*/
domToMutation: function(xmlElement) {
this.arguments_ = [];
for (var x = 0, childNode; childNode = xmlElement.childNodes[x]; x++) {
@@ -88,11 +132,30 @@ Blockly.Blocks['procedures_defnoreturn'] = {
}
}
this.updateParams_();
// Show or hide the statement input.
this.setStatements_(xmlElement.getAttribute('statements') !== 'false');
},
/**
* Populate the mutator's dialog with this block's components.
* @param {!Blockly.Workspace} workspace Mutator's workspace.
* @return {!Blockly.Block} Root block in mutator.
* @this Blockly.Block
*/
decompose: function(workspace) {
var containerBlock = Blockly.Block.obtain(workspace,
'procedures_mutatorcontainer');
'procedures_mutatorcontainer');
containerBlock.initSvg();
// Check/uncheck the allow statement box.
if (this.getInput('RETURN')) {
containerBlock.setFieldValue(this.hasStatements_ ? 'TRUE' : 'FALSE',
'STATEMENTS');
} else {
containerBlock.getInput('STATEMENT_INPUT').setVisible(false);
}
// Parameter list.
var connection = containerBlock.getInput('STACK').connection;
for (var x = 0; x < this.arguments_.length; x++) {
var paramBlock = Blockly.Block.obtain(workspace, 'procedures_mutatorarg');
@@ -108,7 +171,13 @@ Blockly.Blocks['procedures_defnoreturn'] = {
this.workspace, this.arguments_, null);
return containerBlock;
},
/**
* Reconfigure this block based on the mutator dialog's components.
* @param {!Blockly.Block} containerBlock Root block in mutator.
* @this Blockly.Block
*/
compose: function(containerBlock) {
// Parameter list.
this.arguments_ = [];
this.paramIds_ = [];
var paramBlock = containerBlock.getInputTargetBlock('STACK');
@@ -121,23 +190,76 @@ Blockly.Blocks['procedures_defnoreturn'] = {
this.updateParams_();
Blockly.Procedures.mutateCallers(this.getFieldValue('NAME'),
this.workspace, this.arguments_, this.paramIds_);
// Show/hide the statement input.
var hasStatements = containerBlock.getFieldValue('STATEMENTS');
if (hasStatements !== null) {
hasStatements = hasStatements == 'TRUE';
if (this.hasStatements_ != hasStatements) {
if (hasStatements) {
this.setStatements_(true);
// Restore the stack, if one was saved.
var stackConnection = this.getInput('STACK').connection;
if (stackConnection.targetConnection ||
!this.statementConnection_ ||
this.statementConnection_.targetConnection ||
this.statementConnection_.sourceBlock_.workspace !=
this.workspace) {
// Block no longer exists or has been attached elsewhere.
this.statementConnection_ = null;
} else {
stackConnection.connect(this.statementConnection_);
}
} else {
// Save the stack, then disconnect it.
var stackConnection = this.getInput('STACK').connection;
this.statementConnection_ = stackConnection.targetConnection;
if (this.statementConnection_) {
var stackBlock = stackConnection.targetBlock();
stackBlock.setParent(null);
stackBlock.bumpNeighbours_();
}
this.setStatements_(false);
}
}
}
},
/**
* Dispose of any callers.
* @this Blockly.Block
*/
dispose: function() {
// Dispose of any callers.
var name = this.getFieldValue('NAME');
Blockly.Procedures.disposeCallers(name, this.workspace);
// Call parent's destructor.
Blockly.Block.prototype.dispose.apply(this, arguments);
},
/**
* Return the signature of this procedure definition.
* @return {!Array} Tuple containing three elements:
* - the name of the defined procedure,
* - a list of all its arguments,
* - that it DOES NOT have a return value.
* @this Blockly.Block
*/
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.getFieldValue('NAME'), this.arguments_, false];
},
/**
* Return all variables referenced by this block.
* @return {!Array.<string>} List of variable names.
* @this Blockly.Block
*/
getVars: function() {
return this.arguments_;
},
/**
* Notification that a variable is renaming.
* If the name matches one of this block's variables, rename it.
* @param {string} oldName Previous name of variable.
* @param {string} newName Renamed variable.
* @this Blockly.Block
*/
renameVar: function(oldName, newName) {
var change = false;
for (var x = 0; x < this.arguments_.length; x++) {
@@ -160,12 +282,16 @@ Blockly.Blocks['procedures_defnoreturn'] = {
}
}
},
/**
* Add custom menu options to this block's context menu.
* @param {!Array} options List of menu options to add to.
* @this Blockly.Block
*/
customContextMenu: function(options) {
// Add option to create caller.
var option = {enabled: true};
var name = this.getFieldValue('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++) {
@@ -176,26 +302,31 @@ Blockly.Blocks['procedures_defnoreturn'] = {
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 xmlField = goog.dom.createDom('field', null, name);
xmlField.setAttribute('name', 'VAR');
var xmlBlock = goog.dom.createDom('block', null, xmlField);
xmlBlock.setAttribute('type', 'variables_get');
option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock);
options.push(option);
if (!this.isCollapsed()) {
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 xmlField = goog.dom.createDom('field', null, name);
xmlField.setAttribute('name', 'VAR');
var xmlBlock = goog.dom.createDom('block', null, xmlField);
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.
/**
* Block for defining a procedure with a return value.
* @this Blockly.Block
*/
init: function() {
this.setHelpUrl(Blockly.Msg.PROCEDURES_DEFRETURN_HELPURL);
this.setColour(290);
@@ -206,25 +337,31 @@ Blockly.Blocks['procedures_defreturn'] = {
.appendField(new Blockly.FieldTextInput(name,
Blockly.Procedures.rename), 'NAME')
.appendField('', 'PARAMS');
this.appendStatementInput('STACK')
.appendField(Blockly.Msg.PROCEDURES_DEFRETURN_DO);
this.appendValueInput('RETURN')
.setAlign(Blockly.ALIGN_RIGHT)
.appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN);
this.setMutator(new Blockly.Mutator(['procedures_mutatorarg']));
this.setTooltip(Blockly.Msg.PROCEDURES_DEFRETURN_TOOLTIP);
this.arguments_ = [];
this.setStatements_(true);
this.statementConnection_ = null;
},
setStatements_: Blockly.Blocks['procedures_defnoreturn'].setStatements_,
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,
/**
* Return the signature of this procedure definition.
* @return {!Array} Tuple containing three elements:
* - the name of the defined procedure,
* - a list of all its arguments,
* - that it DOES have a return value.
* @this Blockly.Block
*/
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.getFieldValue('NAME'), this.arguments_, true];
},
getVars: Blockly.Blocks['procedures_defnoreturn'].getVars,
@@ -234,73 +371,109 @@ Blockly.Blocks['procedures_defreturn'] = {
};
Blockly.Blocks['procedures_mutatorcontainer'] = {
// Procedure container (for mutator dialog).
/**
* Mutator block for procedure container.
* @this Blockly.Block
*/
init: function() {
this.setColour(290);
this.appendDummyInput()
.appendField(Blockly.Msg.PROCEDURES_MUTATORCONTAINER_TITLE);
this.appendStatementInput('STACK');
this.setTooltip('');
this.appendDummyInput('STATEMENT_INPUT')
.appendField(Blockly.Msg.PROCEDURES_ALLOW_STATEMENTS)
.appendField(new Blockly.FieldCheckbox('TRUE'), 'STATEMENTS');
this.setTooltip(Blockly.Msg.PROCEDURES_MUTATORCONTAINER_TOOLTIP);
this.contextMenu = false;
}
};
Blockly.Blocks['procedures_mutatorarg'] = {
// Procedure argument (for mutator dialog).
/**
* Mutator block for procedure argument.
* @this Blockly.Block
*/
init: function() {
this.setColour(290);
this.appendDummyInput()
.appendField(Blockly.Msg.PROCEDURES_MUTATORARG_TITLE)
.appendField(new Blockly.FieldTextInput('x', this.validator), 'NAME');
.appendField(new Blockly.FieldTextInput('x', this.validator_), 'NAME');
this.setPreviousStatement(true);
this.setNextStatement(true);
this.setTooltip('');
this.setTooltip(Blockly.Msg.PROCEDURES_MUTATORARG_TOOLTIP);
this.contextMenu = false;
},
validator: function(newVar) {
// Merge runs of whitespace. Strip leading and trailing whitespace.
// Beyond this, all names are legal.
/**
* Obtain a valid name for the procedure.
* Merge runs of whitespace. Strip leading and trailing whitespace.
* Beyond this, all names are legal.
* @param {string} newVar User-supplied name.
* @return {?string} Valid name, or null if a name was not specified.
* @private
* @this Blockly.Block
*/
validator_: function(newVar) {
newVar = newVar.replace(/[\s\xa0]+/g, ' ').replace(/^ | $/g, '');
return newVar || null;
}
};
Blockly.Blocks['procedures_callnoreturn'] = {
// Call a procedure with no return value.
/**
* Block for calling a procedure with no return value.
* @this Blockly.Block
*/
init: function() {
this.setHelpUrl(Blockly.Msg.PROCEDURES_CALLNORETURN_HELPURL);
this.setColour(290);
this.appendDummyInput()
.appendField(Blockly.Msg.PROCEDURES_CALLNORETURN_CALL)
.appendField('', 'NAME');
.appendField('', 'NAME')
.appendField(Blockly.Msg.PROCEDURES_CALL_BEFORE_PARAMS, 'WITH');
this.setPreviousStatement(true);
this.setNextStatement(true);
this.setTooltip(Blockly.Msg.PROCEDURES_CALLNORETURN_TOOLTIP);
// Tooltip is set in domToMutation.
this.arguments_ = [];
this.quarkConnections_ = null;
this.quarkArguments_ = null;
},
/**
* Returns the name of the procedure this block calls.
* @return {string} Procedure name.
* @this Blockly.Block
*/
getProcedureCall: function() {
return this.getFieldValue('NAME');
// The NAME field is guaranteed to exist, null will never be returned.
return /** @type {string} */ (this.getFieldValue('NAME'));
},
/**
* Notification that a procedure is renaming.
* If the name matches this block's procedure, rename it.
* @param {string} oldName Previous name of procedure.
* @param {string} newName Renamed procedure.
* @this Blockly.Block
*/
renameProcedure: function(oldName, newName) {
if (Blockly.Names.equals(oldName, this.getFieldValue('NAME'))) {
if (Blockly.Names.equals(oldName, this.getProcedureCall())) {
this.setFieldValue(newName, 'NAME');
this.setTooltip(
(this.outputConnection ? Blockly.Msg.PROCEDURES_CALLRETURN_TOOLTIP
: Blockly.Msg.PROCEDURES_CALLNORETURN_TOOLTIP)
(this.outputConnection ? Blockly.Msg.PROCEDURES_CALLRETURN_TOOLTIP :
Blockly.Msg.PROCEDURES_CALLNORETURN_TOOLTIP)
.replace('%1', newName));
}
},
/**
* Notification that the procedure's parameters have changed.
* @param {!Array.<string>} paramNames New param names, e.g. ['x', 'y', 'z'].
* @param {!Array.<string>} paramIds IDs of params (consistent for each
* parameter through the life of a mutator, regardless of param renaming),
* e.g. ['piua', 'f8b_', 'oi.o'].
* @this Blockly.Block
*/
setProcedureParameters: function(paramNames, paramIds) {
// Data structures for parameters on each call block:
// Data structures:
// 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_']
@@ -362,16 +535,22 @@ Blockly.Blocks['procedures_callnoreturn'] = {
}
}
}
// Add 'with:' if there are parameters.
this.getField_('WITH').setVisible(!!this.arguments_.length);
// Restore rendering and show the changes.
this.rendered = savedRendered;
if (this.rendered) {
this.render();
}
},
/**
* Create XML to represent the (non-editable) name and arguments.
* @return {Element} XML storage element.
* @this Blockly.Block
*/
mutationToDom: function() {
// Save the name and arguments (none of which are editable).
var container = document.createElement('mutation');
container.setAttribute('name', this.getFieldValue('NAME'));
container.setAttribute('name', this.getProcedureCall());
for (var x = 0; x < this.arguments_.length; x++) {
var parameter = document.createElement('arg');
parameter.setAttribute('name', this.arguments_[x]);
@@ -379,13 +558,17 @@ Blockly.Blocks['procedures_callnoreturn'] = {
}
return container;
},
/**
* Parse XML to restore the (non-editable) name and parameters.
* @param {!Element} xmlElement XML storage element.
* @this Blockly.Block
*/
domToMutation: function(xmlElement) {
// Restore the name and parameters.
var name = xmlElement.getAttribute('name');
this.setFieldValue(name, 'NAME');
this.setTooltip(
(this.outputConnection ? Blockly.Msg.PROCEDURES_CALLRETURN_TOOLTIP
: Blockly.Msg.PROCEDURES_CALLNORETURN_TOOLTIP).replace('%1', name));
(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.
@@ -402,6 +585,13 @@ Blockly.Blocks['procedures_callnoreturn'] = {
this.setProcedureParameters(this.arguments_, this.arguments_);
}
},
/**
* Notification that a variable is renaming.
* If the name matches one of this block's variables, rename it.
* @param {string} oldName Previous name of variable.
* @param {string} newName Renamed variable.
* @this Blockly.Block
*/
renameVar: function(oldName, newName) {
for (var x = 0; x < this.arguments_.length; x++) {
if (Blockly.Names.equals(oldName, this.arguments_[x])) {
@@ -410,11 +600,15 @@ Blockly.Blocks['procedures_callnoreturn'] = {
}
}
},
/**
* Add menu option to find the definition block for this call.
* @param {!Array} options List of menu options to add to.
* @this Blockly.Block
*/
customContextMenu: function(options) {
// Add option to find caller.
var option = {enabled: true};
option.text = Blockly.Msg.PROCEDURES_HIGHLIGHT_DEF;
var name = this.getFieldValue('NAME');
var name = this.getProcedureCall();
var workspace = this.workspace;
option.callback = function() {
var def = Blockly.Procedures.getDefinition(name, workspace);
@@ -425,15 +619,19 @@ Blockly.Blocks['procedures_callnoreturn'] = {
};
Blockly.Blocks['procedures_callreturn'] = {
// Call a procedure with a return value.
/**
* Block for calling a procedure with a return value.
* @this Blockly.Block
*/
init: function() {
this.setHelpUrl(Blockly.Msg.PROCEDURES_CALLRETURN_HELPURL);
this.setColour(290);
this.appendDummyInput()
.appendField(Blockly.Msg.PROCEDURES_CALLRETURN_CALL)
.appendField('', 'NAME');
.appendField('', 'NAME')
.appendField(Blockly.Msg.PROCEDURES_CALL_BEFORE_PARAMS, 'WITH');
this.setOutput(true);
this.setTooltip(Blockly.Msg.PROCEDURES_CALLRETURN_TOOLTIP);
// Tooltip is set in domToMutation.
this.arguments_ = [];
this.quarkConnections_ = null;
this.quarkArguments_ = null;
@@ -449,7 +647,10 @@ Blockly.Blocks['procedures_callreturn'] = {
};
Blockly.Blocks['procedures_ifreturn'] = {
// Conditionally return value from a procedure.
/**
* Block for conditionally returning a value from a procedure.
* @this Blockly.Block
*/
init: function() {
this.setHelpUrl('http://c2.com/cgi/wiki?GuardClause');
this.setColour(290);
@@ -464,14 +665,22 @@ Blockly.Blocks['procedures_ifreturn'] = {
this.setTooltip(Blockly.Msg.PROCEDURES_IFRETURN_TOOLTIP);
this.hasReturnValue_ = true;
},
/**
* Create XML to represent whether this block has a return value.
* @return {Element} XML storage element.
* @this Blockly.Block
*/
mutationToDom: function() {
// Save whether this block has a return value.
var container = document.createElement('mutation');
container.setAttribute('value', Number(this.hasReturnValue_));
return container;
},
/**
* Parse XML to restore whether this block has a return value.
* @param {!Element} xmlElement XML storage element.
* @this Blockly.Block
*/
domToMutation: function(xmlElement) {
// Restore whether this block has a return value.
var value = xmlElement.getAttribute('value');
this.hasReturnValue_ = (value == 1);
if (!this.hasReturnValue_) {
@@ -480,6 +689,11 @@ Blockly.Blocks['procedures_ifreturn'] = {
.appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN);
}
},
/**
* Called whenever anything on the workspace changes.
* Add warning if this flow block is not nested inside a loop.
* @this Blockly.Block
*/
onchange: function() {
if (!this.workspace) {
// Block has been deleted.