mirror of
https://github.com/google/blockly.git
synced 2026-01-14 12:27:10 +01:00
Merge pull request #1495 from rachel-fenichel/feature/variables_by_id
Act on variables by ID, not name + type
This commit is contained in:
@@ -266,8 +266,12 @@ Blockly.Blocks['procedures_defnoreturn'] = {
|
||||
*/
|
||||
getVarModels: function() {
|
||||
var vars = [];
|
||||
// Not fully initialized.
|
||||
if (!this.arguments_) {
|
||||
return vars;
|
||||
}
|
||||
for (var i = 0, argName; argName = this.arguments_[i]; i++) {
|
||||
// TODO (#1199): When we switch to tracking variables by ID,
|
||||
// TODO (#1494): When we switch to tracking procedure arguments by ID,
|
||||
// update this.
|
||||
var model = this.workspace.getVariable(argName, '');
|
||||
if (model) {
|
||||
@@ -463,12 +467,13 @@ Blockly.Blocks['procedures_mutatorarg'] = {
|
||||
if (source && source.workspace && source.workspace.options &&
|
||||
source.workspace.options.parentWorkspace) {
|
||||
var workspace = source.workspace.options.parentWorkspace;
|
||||
var variable = workspace.getVariable(newText);
|
||||
var variableType = '';
|
||||
var variable = workspace.getVariable(newText, variableType);
|
||||
// If there is a case change, rename the variable.
|
||||
if (variable && variable.name !== newText) {
|
||||
workspace.renameVariableById(variable.getId(), newText);
|
||||
} else {
|
||||
workspace.createVariable(newText);
|
||||
workspace.createVariable(newText, variableType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -695,9 +695,9 @@ Blockly.Block.prototype.getVarModels = function() {
|
||||
for (var i = 0, input; input = this.inputList[i]; i++) {
|
||||
for (var j = 0, field; field = input.fieldRow[j]; j++) {
|
||||
if (field instanceof Blockly.FieldVariable) {
|
||||
// TODO (#1199): When we switch to tracking variables by ID,
|
||||
// update this.
|
||||
var model = this.workspace.getVariable(field.getValue(), '');
|
||||
var model = this.workspace.getVariableById(field.getValue());
|
||||
// Check if the variable actually exists (and isn't just a potential
|
||||
// variable).
|
||||
if (model) {
|
||||
vars.push(model);
|
||||
}
|
||||
@@ -709,6 +709,7 @@ Blockly.Block.prototype.getVarModels = function() {
|
||||
|
||||
/**
|
||||
* Notification that a variable is renaming.
|
||||
* TODO (#1498): consider deleting this.
|
||||
* If the name matches one of this block's variables, rename it.
|
||||
* @param {string} oldName Previous name of variable.
|
||||
* @param {string} newName Renamed variable.
|
||||
@@ -724,6 +725,41 @@ Blockly.Block.prototype.renameVar = function(oldName, newName) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Notification that a variable is renaming but keeping the same ID. If the
|
||||
* variable is in use on this block, rerender to show the new name.
|
||||
* @param {!Blockly.VariableModel} variable The variable being renamed.
|
||||
* @public
|
||||
*/
|
||||
Blockly.Block.prototype.updateVarName = function(variable) {
|
||||
for (var i = 0, input; input = this.inputList[i]; i++) {
|
||||
for (var j = 0, field; field = input.fieldRow[j]; j++) {
|
||||
if (field instanceof Blockly.FieldVariable &&
|
||||
variable.getId() == field.getValue()) {
|
||||
field.setText(variable.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Notification that a variable is renaming.
|
||||
* If the name matches one of this block's variables, rename it.
|
||||
* @param {string} oldId ID of variable to rename.
|
||||
* @param {string} newId ID of new variable. May be the same as oldId, but with
|
||||
* an updated name.
|
||||
*/
|
||||
Blockly.Block.prototype.renameVarById = function(oldId, newId) {
|
||||
for (var i = 0, input; input = this.inputList[i]; i++) {
|
||||
for (var j = 0, field; field = input.fieldRow[j]; j++) {
|
||||
if (field instanceof Blockly.FieldVariable &&
|
||||
oldId == field.getValue()) {
|
||||
field.setValue(newId);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the language-neutral value from the field of a block.
|
||||
* @param {string} name The name of the field.
|
||||
|
||||
@@ -47,15 +47,24 @@ goog.require('goog.string');
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.FieldVariable = function(varname, opt_validator, opt_variableTypes) {
|
||||
Blockly.FieldVariable.superClass_.constructor.call(this,
|
||||
Blockly.FieldVariable.dropdownCreate, opt_validator);
|
||||
this.setValue(varname || '');
|
||||
// The FieldDropdown constructor would call setValue, which might create a
|
||||
// spurious variable. Just do the relevant parts of the constructor.
|
||||
this.menuGenerator_ = Blockly.FieldVariable.dropdownCreate;
|
||||
this.size_ = new goog.math.Size(0, Blockly.BlockSvg.MIN_BLOCK_Y);
|
||||
this.setValidator(opt_validator);
|
||||
// TODO (#1499): Add opt_default_type to match default value. If not set, ''.
|
||||
this.defaultVariableName = (varname || '');
|
||||
this.defaultType_ = '';
|
||||
this.variableTypes = opt_variableTypes;
|
||||
this.value_ = null;
|
||||
};
|
||||
goog.inherits(Blockly.FieldVariable, Blockly.FieldDropdown);
|
||||
|
||||
|
||||
/**
|
||||
* Install this dropdown on a block.
|
||||
* Initialize everything needed to render this field. This includes making sure
|
||||
* that the field's value is valid.
|
||||
* @public
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.init = function() {
|
||||
if (this.fieldGroup_) {
|
||||
@@ -68,21 +77,30 @@ Blockly.FieldVariable.prototype.init = function() {
|
||||
this.initModel();
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize the model for this field if it has not already been initialized.
|
||||
* If the value has not been set to a variable by the first render, we make up a
|
||||
* variable rather than let the value be invalid.
|
||||
* @package
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.initModel = function() {
|
||||
if (!this.getValue()) {
|
||||
// Variables without names get uniquely named for this workspace.
|
||||
var workspace =
|
||||
this.sourceBlock_.isInFlyout ?
|
||||
this.sourceBlock_.workspace.targetWorkspace :
|
||||
this.sourceBlock_.workspace;
|
||||
this.setValue(Blockly.Variables.generateUniqueName(workspace));
|
||||
}
|
||||
// If the selected variable doesn't exist yet, create it.
|
||||
// For instance, some blocks in the toolbox have variable dropdowns filled
|
||||
// in by default.
|
||||
if (!this.sourceBlock_.isInFlyout) {
|
||||
this.sourceBlock_.workspace.createVariable(this.getValue());
|
||||
if (this.variable_) {
|
||||
return; // Initialization already happened.
|
||||
}
|
||||
this.workspace_ = this.sourceBlock_.workspace;
|
||||
var variable = Blockly.Variables.getOrCreateVariable(
|
||||
this.workspace_, null, this.defaultVariableName, this.defaultType_);
|
||||
this.setValue(variable.getId());
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispose of this field.
|
||||
* @public
|
||||
*/
|
||||
Blockly.FieldVariable.dispose = function() {
|
||||
Blockly.FieldVariable.superClass_.dispose.call(this);
|
||||
this.workspace_ = null;
|
||||
this.variableMap_ = null;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -96,39 +114,69 @@ Blockly.FieldVariable.prototype.setSourceBlock = function(block) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the variable's name (use a variableDB to convert into a real name).
|
||||
* Unline a regular dropdown, variables are literal and have no neutral value.
|
||||
* @return {string} Current text.
|
||||
* Get the variable's ID.
|
||||
* @return {string} Current variable's ID.
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.getValue = function() {
|
||||
return this.getText();
|
||||
return this.variable_ ? this.variable_.getId() : '';
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the variable name.
|
||||
* @param {string} value New text.
|
||||
* Get the text from this field.
|
||||
* @return {string} Current text.
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.setValue = function(value) {
|
||||
var newValue = value;
|
||||
var newText = value;
|
||||
Blockly.FieldVariable.prototype.getText = function() {
|
||||
return this.variable_ ? this.variable_.name : '';
|
||||
};
|
||||
|
||||
if (this.sourceBlock_) {
|
||||
var variable = this.sourceBlock_.workspace.getVariableById(value);
|
||||
if (variable) {
|
||||
newText = variable.name;
|
||||
}
|
||||
// TODO(marisaleung): Remove name lookup after converting all Field Variable
|
||||
// instances to use ID instead of name.
|
||||
else if (variable = this.sourceBlock_.workspace.getVariable(value)) {
|
||||
newValue = variable.getId();
|
||||
}
|
||||
if (Blockly.Events.isEnabled()) {
|
||||
Blockly.Events.fire(new Blockly.Events.BlockChange(
|
||||
this.sourceBlock_, 'field', this.name, this.value_, newValue));
|
||||
/**
|
||||
* Set the variable ID.
|
||||
* @param {string} id New variable ID, which must reference an existing
|
||||
* variable.
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.setValue = function(id) {
|
||||
// What do I do when id is null? That happens when undoing a change event
|
||||
// for the first time the value was set.
|
||||
var workspace = this.sourceBlock_.workspace;
|
||||
var variable = Blockly.Variables.getVariable(workspace, id);
|
||||
|
||||
if (!variable) {
|
||||
throw new Error('Variable id doesn\'t point to a real variable! ID was ' +
|
||||
id);
|
||||
}
|
||||
// Type checks!
|
||||
var type = variable.type;
|
||||
if (!this.typeIsAllowed_(type)) {
|
||||
throw new Error('Variable type doesn\'t match this field! Type was ' +
|
||||
type);
|
||||
}
|
||||
if (this.sourceBlock_ && Blockly.Events.isEnabled()) {
|
||||
var oldValue = this.variable_ ? this.variable_.getId() : null;
|
||||
Blockly.Events.fire(new Blockly.Events.BlockChange(
|
||||
this.sourceBlock_, 'field', this.name, oldValue, variable.getId()));
|
||||
}
|
||||
this.variable_ = variable;
|
||||
this.value_ = id;
|
||||
this.setText(variable.name);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check whether the given variable type is allowed on this field.
|
||||
* @param {string} type The type to check.
|
||||
* @return {boolean} True if the type is in the list of allowed types.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.typeIsAllowed_ = function(type) {
|
||||
var typeList = this.getVariableTypes_();
|
||||
if (!typeList) {
|
||||
return true; // If it's null, all types are valid.
|
||||
}
|
||||
for (var i = 0; i < typeList.length; i++) {
|
||||
if (type == typeList[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
this.value_ = newValue;
|
||||
this.setText(newText);
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -138,6 +186,8 @@ Blockly.FieldVariable.prototype.setValue = function(value) {
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.getVariableTypes_ = function() {
|
||||
// TODO: Why does this happen every time, instead of once when the workspace
|
||||
// is set? Do we expect the variable types to change that much?
|
||||
var variableTypes = this.variableTypes;
|
||||
if (variableTypes === null) {
|
||||
// If variableTypes is null, return all variable types.
|
||||
@@ -163,10 +213,12 @@ Blockly.FieldVariable.prototype.getVariableTypes_ = function() {
|
||||
* @this {Blockly.FieldVariable}
|
||||
*/
|
||||
Blockly.FieldVariable.dropdownCreate = function() {
|
||||
if (!this.variable_) {
|
||||
throw new Error('Tried to call dropdownCreate on a variable field with no' +
|
||||
' variable selected.');
|
||||
}
|
||||
var variableModelList = [];
|
||||
var name = this.getText();
|
||||
// Don't create a new variable if there is nothing selected.
|
||||
var createSelectedVariable = name ? true : false;
|
||||
var workspace = null;
|
||||
if (this.sourceBlock_) {
|
||||
workspace = this.sourceBlock_.workspace;
|
||||
@@ -181,20 +233,9 @@ Blockly.FieldVariable.dropdownCreate = function() {
|
||||
var variables = workspace.getVariablesOfType(variableType);
|
||||
variableModelList = variableModelList.concat(variables);
|
||||
}
|
||||
for (var i = 0; i < variableModelList.length; i++) {
|
||||
if (createSelectedVariable &&
|
||||
goog.string.caseInsensitiveEquals(variableModelList[i].name, name)) {
|
||||
createSelectedVariable = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ensure that the currently selected variable is an option.
|
||||
if (createSelectedVariable && workspace) {
|
||||
var newVar = workspace.createVariable(name);
|
||||
variableModelList.push(newVar);
|
||||
}
|
||||
variableModelList.sort(Blockly.VariableModel.compareByName);
|
||||
|
||||
var options = [];
|
||||
for (var i = 0; i < variableModelList.length; i++) {
|
||||
// Set the UUID as the internal representation of the variable.
|
||||
@@ -205,6 +246,7 @@ Blockly.FieldVariable.dropdownCreate = function() {
|
||||
options.push([Blockly.Msg.DELETE_VARIABLE.replace('%1', name),
|
||||
Blockly.DELETE_VARIABLE_ID]);
|
||||
}
|
||||
|
||||
return options;
|
||||
};
|
||||
|
||||
@@ -217,31 +259,24 @@ Blockly.FieldVariable.dropdownCreate = function() {
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.onItemSelected = function(menu, menuItem) {
|
||||
var id = menuItem.getValue();
|
||||
// TODO(marisaleung): change setValue() to take in an ID as the parameter.
|
||||
// Then remove itemText.
|
||||
var itemText;
|
||||
if (this.sourceBlock_ && this.sourceBlock_.workspace) {
|
||||
var workspace = this.sourceBlock_.workspace;
|
||||
var variable = workspace.getVariableById(id);
|
||||
// If the item selected is a variable, set itemText to the variable name.
|
||||
if (variable) {
|
||||
itemText = variable.name;
|
||||
} else if (id == Blockly.RENAME_VARIABLE_ID) {
|
||||
if (id == Blockly.RENAME_VARIABLE_ID) {
|
||||
// Rename variable.
|
||||
var currentName = this.getText();
|
||||
variable = workspace.getVariable(currentName);
|
||||
Blockly.Variables.renameVariable(workspace, variable);
|
||||
Blockly.Variables.renameVariable(workspace, this.variable_);
|
||||
return;
|
||||
} else if (id == Blockly.DELETE_VARIABLE_ID) {
|
||||
// Delete variable.
|
||||
workspace.deleteVariable(this.getText());
|
||||
workspace.deleteVariableById(this.variable_.getId());
|
||||
return;
|
||||
}
|
||||
|
||||
// Call any validation function, and allow it to override.
|
||||
itemText = this.callValidator(itemText);
|
||||
}
|
||||
if (itemText !== null) {
|
||||
this.setValue(itemText);
|
||||
// TODO: Call any validation function, and allow it to override.
|
||||
// For now it's unclear whether the validator should act on the id.
|
||||
//var validatedId = this.callValidator(variable.getId());
|
||||
}
|
||||
// if (variable.getId() !== null) {
|
||||
// this.setValue(validatedId);
|
||||
// }
|
||||
this.setValue(id);
|
||||
};
|
||||
|
||||
@@ -542,6 +542,9 @@ Blockly.Flyout.prototype.clearOldBlocks_ = function() {
|
||||
button.dispose();
|
||||
}
|
||||
this.buttons_.length = 0;
|
||||
|
||||
// Clear potential variables from the previous showing.
|
||||
this.workspace_.getPotentialVariableMap().clear();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -596,33 +599,6 @@ Blockly.Flyout.prototype.onMouseDown_ = function(e) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to get the list of variables that have been added to the
|
||||
* workspace after adding a new block, using the given list of variables that
|
||||
* were in the workspace before the new block was added.
|
||||
* @param {!Array.<!Blockly.VariableModel>} originalVariables The array of
|
||||
* variables that existed in the workspace before adding the new block.
|
||||
* @return {!Array.<!Blockly.VariableModel>} The new array of variables that were
|
||||
* freshly added to the workspace after creating the new block, or [] if no
|
||||
* new variables were added to the workspace.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Flyout.prototype.getAddedVariables_ = function(originalVariables) {
|
||||
var allCurrentVariables = this.targetWorkspace_.getAllVariables();
|
||||
var addedVariables = [];
|
||||
if (originalVariables.length != allCurrentVariables.length) {
|
||||
for (var i = 0; i < allCurrentVariables.length; i++) {
|
||||
var variable = allCurrentVariables[i];
|
||||
// For any variable that is present in allCurrentVariables but not
|
||||
// present in originalVariables, add the variable to addedVariables.
|
||||
if (!originalVariables.includes(variable)) {
|
||||
addedVariables.push(variable);
|
||||
}
|
||||
}
|
||||
}
|
||||
return addedVariables;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a copy of this block on the workspace.
|
||||
* @param {!Blockly.BlockSvg} originalBlock The block to copy from the flyout.
|
||||
@@ -643,7 +619,8 @@ Blockly.Flyout.prototype.createBlock = function(originalBlock) {
|
||||
Blockly.Events.enable();
|
||||
}
|
||||
|
||||
var newVariables = this.getAddedVariables_(variablesBeforeCreation);
|
||||
var newVariables = Blockly.Variables.getAddedVariables(this.targetWorkspace_,
|
||||
variablesBeforeCreation);
|
||||
|
||||
if (Blockly.Events.isEnabled()) {
|
||||
Blockly.Events.setGroup(true);
|
||||
|
||||
@@ -60,47 +60,78 @@ Blockly.VariableMap.prototype.clear = function() {
|
||||
|
||||
/**
|
||||
* Rename the given variable by updating its name in the variable map.
|
||||
* @param {Blockly.VariableModel} variable Variable to rename.
|
||||
* @param {!Blockly.VariableModel} variable Variable to rename.
|
||||
* @param {string} newName New variable name.
|
||||
* @param {string=} opt_type The type of the variable to create if variable was
|
||||
* null.
|
||||
* @package
|
||||
*/
|
||||
Blockly.VariableMap.prototype.renameVariable = function(variable, newName,
|
||||
opt_type) {
|
||||
var type = variable ? variable.type : (opt_type || '');
|
||||
var newVariable = this.getVariable(newName, type);
|
||||
var variableIndex = -1;
|
||||
var newVariableIndex = -1;
|
||||
Blockly.VariableMap.prototype.renameVariable = function(variable, newName) {
|
||||
var type = variable.type;
|
||||
var conflictVar = this.getVariable(newName, type);
|
||||
var blocks = this.workspace.getAllBlocks();
|
||||
Blockly.Events.setGroup(true);
|
||||
// The IDs may match if the rename is a simple case change (name1 -> Name1).
|
||||
if (!conflictVar || conflictVar.getId() == variable.getId()) {
|
||||
this.renameVariableAndUses_(variable, newName, blocks);
|
||||
} else {
|
||||
this.renameVariableWithConflict_(variable, newName, conflictVar, blocks);
|
||||
}
|
||||
Blockly.Events.setGroup(false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the name of the given variable and refresh all references to it.
|
||||
* The new name must not conflict with any existing variable names.
|
||||
* @param {!Blockly.VariableModel} variable Variable to rename.
|
||||
* @param {string} newName New variable name.
|
||||
* @param {!Array.<!Blockly.Block>} blocks The list of all blocks in the
|
||||
* workspace.
|
||||
* @private
|
||||
*/
|
||||
Blockly.VariableMap.prototype.renameVariableAndUses_ = function(variable,
|
||||
newName, blocks) {
|
||||
Blockly.Events.fire(new Blockly.Events.VarRename(variable, newName));
|
||||
variable.name = newName;
|
||||
for (var i = 0; i < blocks.length; i++) {
|
||||
blocks[i].updateVarName(variable);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the name of the given variable to the same name as an existing
|
||||
* variable. The two variables are coalesced into a single variable with the ID
|
||||
* of the existing variable that was already using newName.
|
||||
* Refresh all references to the variable.
|
||||
* @param {!Blockly.VariableModel} variable Variable to rename.
|
||||
* @param {string} newName New variable name.
|
||||
* @param {!Blockly.VariableModel} conflictVar The variable that was already
|
||||
* using newName.
|
||||
* @param {!Array.<!Blockly.Block>} blocks The list of all blocks in the
|
||||
* workspace.
|
||||
* @private
|
||||
*/
|
||||
Blockly.VariableMap.prototype.renameVariableWithConflict_ = function(variable,
|
||||
newName, conflictVar, blocks) {
|
||||
var type = variable.type;
|
||||
var oldCase = conflictVar.name;
|
||||
|
||||
if (newName != oldCase) {
|
||||
// Simple rename to change the case and update references.
|
||||
this.renameVariableAndUses_(conflictVar, newName, blocks);
|
||||
}
|
||||
|
||||
// These blocks now refer to a different variable.
|
||||
// These will fire change events.
|
||||
for (var i = 0; i < blocks.length; i++) {
|
||||
blocks[i].renameVarById(variable.getId(), conflictVar.getId());
|
||||
}
|
||||
|
||||
// Finally delete the original variable, which is now unreferenced.
|
||||
Blockly.Events.fire(new Blockly.Events.VarDelete(variable));
|
||||
// And remove it from the list.
|
||||
var variableList = this.getVariablesOfType(type);
|
||||
if (variable) {
|
||||
variableIndex = variableList.indexOf(variable);
|
||||
}
|
||||
if (newVariable) { // see if I can get rid of newVariable dependency
|
||||
newVariableIndex = variableList.indexOf(newVariable);
|
||||
}
|
||||
var variableIndex = variableList.indexOf(variable);
|
||||
this.variableMap_[type].splice(variableIndex, 1);
|
||||
|
||||
if (variableIndex == -1 && newVariableIndex == -1) {
|
||||
this.createVariable(newName, '');
|
||||
console.log('Tried to rename an non-existent variable.');
|
||||
} else if (variableIndex == newVariableIndex ||
|
||||
variableIndex != -1 && newVariableIndex == -1) {
|
||||
// Only changing case, or renaming to a completely novel name.
|
||||
var variableToRename = this.variableMap_[type][variableIndex];
|
||||
Blockly.Events.fire(new Blockly.Events.VarRename(variableToRename,
|
||||
newName));
|
||||
variableToRename.name = newName;
|
||||
} else if (variableIndex != -1 && newVariableIndex != -1) {
|
||||
// Renaming one existing variable to another existing variable.
|
||||
// The case might have changed, so we update the destination ID.
|
||||
var variableToRename = this.variableMap_[type][newVariableIndex];
|
||||
Blockly.Events.fire(new Blockly.Events.VarRename(variableToRename,
|
||||
newName));
|
||||
var variableToDelete = this.variableMap_[type][variableIndex];
|
||||
Blockly.Events.fire(new Blockly.Events.VarDelete(variableToDelete));
|
||||
variableToRename.name = newName;
|
||||
this.variableMap_[type].splice(variableIndex, 1);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -64,14 +64,13 @@ Blockly.Variables.allUsedVariables = function(root) {
|
||||
var variableHash = Object.create(null);
|
||||
// Iterate through every block and add each variable to the hash.
|
||||
for (var x = 0; x < blocks.length; x++) {
|
||||
// TODO (#1199) Switch to IDs.
|
||||
var blockVariables = blocks[x].getVars();
|
||||
var blockVariables = blocks[x].getVarModels();
|
||||
if (blockVariables) {
|
||||
for (var y = 0; y < blockVariables.length; y++) {
|
||||
var varName = blockVariables[y];
|
||||
// Variable name may be null if the block is only half-built.
|
||||
if (varName) {
|
||||
variableHash[varName.toLowerCase()] = varName;
|
||||
var variable = blockVariables[y];
|
||||
// Variable ID may be null if the block is only half-built.
|
||||
if (variable.getId()) {
|
||||
variableHash[variable.name.toLowerCase()] = variable.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -269,30 +268,31 @@ Blockly.Variables.createVariable = function(workspace, opt_callback, opt_type) {
|
||||
* Rename a variable with the given workspace, variableType, and oldName.
|
||||
* @param {!Blockly.Workspace} workspace The workspace on which to rename the
|
||||
* variable.
|
||||
* @param {?Blockly.VariableModel} variable Variable to rename.
|
||||
* @param {Blockly.VariableModel} variable Variable to rename.
|
||||
* @param {function(?string=)=} opt_callback A callback. It will
|
||||
* be passed an acceptable new variable name, or null if change is to be
|
||||
* aborted (cancel button), or undefined if an existing variable was chosen.
|
||||
*/
|
||||
Blockly.Variables.renameVariable = function(workspace, variable,
|
||||
opt_callback) {
|
||||
opt_callback) {
|
||||
// This function needs to be named so it can be called recursively.
|
||||
var promptAndCheckWithAlert = function(defaultName) {
|
||||
Blockly.Variables.promptName(
|
||||
Blockly.Msg.RENAME_VARIABLE_TITLE.replace('%1', variable.name), defaultName,
|
||||
function(newName) {
|
||||
if (newName) {
|
||||
workspace.renameVariable(variable.name, newName);
|
||||
if (opt_callback) {
|
||||
opt_callback(newName);
|
||||
var promptText =
|
||||
Blockly.Msg.RENAME_VARIABLE_TITLE.replace('%1', variable.name);
|
||||
Blockly.Variables.promptName(promptText, defaultName,
|
||||
function(newName) {
|
||||
if (newName) {
|
||||
workspace.renameVariableById(variable.getId(), newName);
|
||||
if (opt_callback) {
|
||||
opt_callback(newName);
|
||||
}
|
||||
} else {
|
||||
// User canceled prompt without a value.
|
||||
if (opt_callback) {
|
||||
opt_callback(null);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// User canceled prompt without a value.
|
||||
if (opt_callback) {
|
||||
opt_callback(null);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
promptAndCheckWithAlert('');
|
||||
};
|
||||
@@ -330,12 +330,122 @@ Blockly.Variables.promptName = function(promptText, defaultText, callback) {
|
||||
Blockly.Variables.generateVariableFieldXml_ = function(variableModel) {
|
||||
// The variable name may be user input, so it may contain characters that need
|
||||
// to be escaped to create valid XML.
|
||||
var element = goog.dom.createDom('field');
|
||||
element.setAttribute('name', 'VAR');
|
||||
element.setAttribute('variabletype', variableModel.type);
|
||||
element.setAttribute('id', variableModel.getId());
|
||||
element.textContent = variableModel.name;
|
||||
|
||||
var xmlString = Blockly.Xml.domToText(element);
|
||||
return xmlString;
|
||||
var typeString = variableModel.type;
|
||||
if (typeString == '') {
|
||||
typeString = '\'\'';
|
||||
}
|
||||
var text = '<field name="VAR" id="' + variableModel.getId() +
|
||||
'" variabletype="' + typeString +
|
||||
'">' + goog.string.htmlEscape(variableModel.name) + '</field>';
|
||||
return text;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to look up or create a variable on the given workspace.
|
||||
* If no variable exists, creates and returns it.
|
||||
* @param {!Blockly.Workspace} workspace The workspace to search for the
|
||||
* variable. It may be a flyout workspace or main workspace.
|
||||
* @param {string} id The ID to use to look up or create the variable, or null.
|
||||
* @param {string} name The string to use to look up or create the variable,
|
||||
* @param {string} type The type to use to look up or create the variable.
|
||||
* @return {!Blockly.VariableModel} The variable corresponding to the given ID
|
||||
* or name + type combination.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Variables.getOrCreateVariable = function(workspace, id, name, type) {
|
||||
var variable = Blockly.Variables.getVariable(workspace, id, name, type);
|
||||
if (!variable) {
|
||||
variable = Blockly.Variables.createVariable_(workspace, id, name, type);
|
||||
}
|
||||
return variable;
|
||||
};
|
||||
|
||||
/**
|
||||
* Look up a variable on the given workspace.
|
||||
* Always looks in the main workspace before looking in the flyout workspace.
|
||||
* Always prefers lookup by ID to lookup by name + type.
|
||||
* @param {!Blockly.Workspace} workspace The workspace to search for the
|
||||
* variable. It may be a flyout workspace or main workspace.
|
||||
* @param {string} id The ID to use to look up the variable, or null.
|
||||
* @param {string=} opt_name The string to use to look up the variable. Only
|
||||
* used if lookup by ID fails.
|
||||
* @param {string=} opt_type The type to use to look up the variable. Only used
|
||||
* if lookup by ID fails.
|
||||
* @return {?Blockly.VariableModel} The variable corresponding to the given ID
|
||||
* or name + type combination, or null if not found.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Variables.getVariable = function(workspace, id, opt_name, opt_type) {
|
||||
var potentialVariableMap = workspace.getPotentialVariableMap();
|
||||
// Try to just get the variable, by ID if possible.
|
||||
if (id) {
|
||||
// Look in the real variable map before checking the potential variable map.
|
||||
var variable = workspace.getVariableById(id);
|
||||
if (!variable && potentialVariableMap) {
|
||||
variable = potentialVariableMap.getVariableById(id);
|
||||
}
|
||||
} else if (opt_name && (opt_type != undefined)){
|
||||
// Otherwise look up by name and type.
|
||||
var variable = workspace.getVariable(opt_name, opt_type);
|
||||
if (!variable && potentialVariableMap) {
|
||||
variable = potentialVariableMap.getVariable(opt_name, opt_type);
|
||||
}
|
||||
}
|
||||
return variable;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to create a variable on the given workspace.
|
||||
* @param {!Blockly.Workspace} workspace The workspace in which to create the
|
||||
* variable. It may be a flyout workspace or main workspace.
|
||||
* @param {string} id The ID to use to create the variable, or null.
|
||||
* @param {string} name The string to use to create the variable.
|
||||
* @param {string} type The type to use to create the variable.
|
||||
* @return {!Blockly.VariableModel} The variable corresponding to the given ID
|
||||
* or name + type combination.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Variables.createVariable_ = function(workspace, id, name, type) {
|
||||
var potentialVariableMap = workspace.getPotentialVariableMap();
|
||||
// Variables without names get uniquely named for this workspace.
|
||||
if (!name) {
|
||||
var ws = workspace.isFlyout ? workspace.targetWorkspace : workspace;
|
||||
name = Blockly.Variables.generateUniqueName(ws);
|
||||
}
|
||||
|
||||
// Create a potential variable if in the flyout.
|
||||
if (potentialVariableMap) {
|
||||
var variable = potentialVariableMap.createVariable(name, type, id);
|
||||
} else { // In the main workspace, create a real variable.
|
||||
var variable = workspace.createVariable(name, type, id);
|
||||
}
|
||||
return variable;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to get the list of variables that have been added to the
|
||||
* workspace after adding a new block, using the given list of variables that
|
||||
* were in the workspace before the new block was added.
|
||||
* @param {!Blockly.Workspace} workspace The workspace to inspect.
|
||||
* @param {!Array.<!Blockly.VariableModel>} originalVariables The array of
|
||||
* variables that existed in the workspace before adding the new block.
|
||||
* @return {!Array.<!Blockly.VariableModel>} The new array of variables that were
|
||||
* freshly added to the workspace after creating the new block, or [] if no
|
||||
* new variables were added to the workspace.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Variables.getAddedVariables = function(workspace, originalVariables) {
|
||||
var allCurrentVariables = workspace.getAllVariables();
|
||||
var addedVariables = [];
|
||||
if (originalVariables.length != allCurrentVariables.length) {
|
||||
for (var i = 0; i < allCurrentVariables.length; i++) {
|
||||
var variable = allCurrentVariables[i];
|
||||
// For any variable that is present in allCurrentVariables but not
|
||||
// present in originalVariables, add the variable to addedVariables.
|
||||
if (!originalVariables.includes(variable)) {
|
||||
addedVariables.push(variable);
|
||||
}
|
||||
}
|
||||
}
|
||||
return addedVariables;
|
||||
};
|
||||
|
||||
@@ -84,6 +84,18 @@ Blockly.Workspace = function(opt_options) {
|
||||
* @private
|
||||
*/
|
||||
this.variableMap_ = new Blockly.VariableMap(this);
|
||||
|
||||
/**
|
||||
* Blocks in the flyout can refer to variables that don't exist in the
|
||||
* workspace. For instance, the "get item in list" block refers to an "item"
|
||||
* variable regardless of whether the variable has been created yet.
|
||||
* A FieldVariable must always refer to a Blockly.VariableModel. We reconcile
|
||||
* these by tracking "potential" variables in the flyout. These variables
|
||||
* become real when references to them are dragged into the main workspace.
|
||||
* @type {!Blockly.VariableMap}
|
||||
* @private
|
||||
*/
|
||||
this.potentialVariableMap_ = new Blockly.VariableMap(this);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -197,91 +209,7 @@ Blockly.Workspace.prototype.clear = function() {
|
||||
Blockly.Events.setGroup(false);
|
||||
}
|
||||
this.variableMap_.clear();
|
||||
};
|
||||
|
||||
/**
|
||||
* Walk the workspace and update the map of variables to only contain ones in
|
||||
* use on the workspace. Use when loading new workspaces from disk.
|
||||
* @param {boolean} clear True if the old variable map should be cleared.
|
||||
*/
|
||||
Blockly.Workspace.prototype.updateVariableStore = function(clear) {
|
||||
// TODO: Sort
|
||||
if (this.isFlyout) {
|
||||
return;
|
||||
}
|
||||
var variableNames = Blockly.Variables.allUsedVariables(this);
|
||||
var varList = [];
|
||||
for (var i = 0, name; name = variableNames[i]; i++) {
|
||||
// Get variable model with the used variable name.
|
||||
var tempVar = this.getVariable(name);
|
||||
if (tempVar) {
|
||||
varList.push({'name': tempVar.name, 'type': tempVar.type,
|
||||
'id': tempVar.getId()});
|
||||
} else {
|
||||
varList.push({'name': name, 'type': null, 'id': null});
|
||||
// TODO(marisaleung): Use variable.type and variable.getId() once variable
|
||||
// instances are storing more than just name.
|
||||
}
|
||||
}
|
||||
if (clear) {
|
||||
this.variableMap_.clear();
|
||||
}
|
||||
// Update the list in place so that the flyout's references stay correct.
|
||||
for (var i = 0, varDict; varDict = varList[i]; i++) {
|
||||
if (!this.getVariable(varDict.name)) {
|
||||
this.createVariable(varDict.name, varDict.type, varDict.id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Rename a variable by updating its name in the variable map. Identify the
|
||||
* variable to rename with the given variable.
|
||||
* @param {?Blockly.VariableModel} variable Variable to rename.
|
||||
* @param {string} newName New variable name.
|
||||
* @param {string=} opt_type The type of the variable to create if variable was
|
||||
* null.
|
||||
*/
|
||||
Blockly.Workspace.prototype.renameVariableInternal_ = function(
|
||||
variable, newName, opt_type) {
|
||||
var type = variable ? variable.type : (opt_type || '');
|
||||
var newVariable = this.getVariable(newName, type);
|
||||
var oldCase;
|
||||
|
||||
// Find if newVariable case is different.
|
||||
if (newVariable && newVariable.name != newName) {
|
||||
oldCase = newVariable.name;
|
||||
}
|
||||
|
||||
Blockly.Events.setGroup(true);
|
||||
var blocks = this.getAllBlocks();
|
||||
// Iterate through every block and update name.
|
||||
for (var i = 0; i < blocks.length; i++) {
|
||||
blocks[i].renameVar(variable.name, newName);
|
||||
if (oldCase) {
|
||||
blocks[i].renameVar(oldCase, newName);
|
||||
}
|
||||
}
|
||||
this.variableMap_.renameVariable(variable, newName, type);
|
||||
Blockly.Events.setGroup(false);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Rename a variable by updating its name in the variable map. Identify the
|
||||
* variable to rename with the given name.
|
||||
* TODO (#1199): Possibly delete this function.
|
||||
* @param {string} oldName Variable to rename.
|
||||
* @param {string} newName New variable name.
|
||||
* @param {string=} opt_type The type of the variable. If not provided it
|
||||
* defaults to the empty string, which is a specific type.
|
||||
*/
|
||||
Blockly.Workspace.prototype.renameVariable = function(oldName, newName,
|
||||
opt_type) {
|
||||
var type = opt_type || '';
|
||||
// Warning: Prefer to use renameVariableById.
|
||||
var variable = this.getVariable(oldName, type);
|
||||
this.renameVariableInternal_(variable, newName, opt_type);
|
||||
this.potentialVariableMap_.clear();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -292,7 +220,11 @@ Blockly.Workspace.prototype.renameVariable = function(oldName, newName,
|
||||
*/
|
||||
Blockly.Workspace.prototype.renameVariableById = function(id, newName) {
|
||||
var variable = this.getVariableById(id);
|
||||
this.renameVariableInternal_(variable, newName);
|
||||
if (!variable) {
|
||||
throw new Error('Tried to rename a variable that didn\'t exist. ID: ' + id);
|
||||
}
|
||||
|
||||
this.variableMap_.renameVariable(variable, newName);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -312,14 +244,10 @@ Blockly.Workspace.prototype.createVariable = function(name, opt_type, opt_id) {
|
||||
|
||||
/**
|
||||
* Find all the uses of a named variable.
|
||||
* TODO (#1199): Possibly delete this function.
|
||||
* @param {string} name Name of variable.
|
||||
* @param {string=} opt_type The type of the variable. If not provided it
|
||||
* defaults to the empty string, which is a specific type.
|
||||
* @param {string} id ID of the variable to find.
|
||||
* @return {!Array.<!Blockly.Block>} Array of block usages.
|
||||
*/
|
||||
Blockly.Workspace.prototype.getVariableUses = function(name, opt_type) {
|
||||
var type = opt_type || '';
|
||||
Blockly.Workspace.prototype.getVariableUsesById = function(id) {
|
||||
var uses = [];
|
||||
var blocks = this.getAllBlocks();
|
||||
// Iterate through every block and check the name.
|
||||
@@ -327,14 +255,7 @@ Blockly.Workspace.prototype.getVariableUses = function(name, opt_type) {
|
||||
var blockVariables = blocks[i].getVarModels();
|
||||
if (blockVariables) {
|
||||
for (var j = 0; j < blockVariables.length; j++) {
|
||||
var varModel = blockVariables[j];
|
||||
var varName = varModel.name;
|
||||
// Skip variables of the wrong type.
|
||||
if (varModel.type != type) {
|
||||
continue;
|
||||
}
|
||||
// Variable name may be null if the block is only half-built.
|
||||
if (varName && name && Blockly.Names.equals(varName, name)) {
|
||||
if (blockVariables[j].getId() == id) {
|
||||
uses.push(blocks[i]);
|
||||
}
|
||||
}
|
||||
@@ -343,49 +264,6 @@ Blockly.Workspace.prototype.getVariableUses = function(name, opt_type) {
|
||||
return uses;
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete a variable by the passed in name and all of its uses from this
|
||||
* workspace. May prompt the user for confirmation.
|
||||
* TODO (#1199): Possibly delete this function.
|
||||
* @param {string} name Name of variable to delete.
|
||||
* @param {string=} opt_type The type of the variable. If not provided it
|
||||
* defaults to the empty string, which is a specific type.
|
||||
*/
|
||||
Blockly.Workspace.prototype.deleteVariable = function(name, opt_type) {
|
||||
var type = opt_type || '';
|
||||
// Check whether this variable is a function parameter before deleting.
|
||||
var uses = this.getVariableUses(name, type);
|
||||
for (var i = 0, block; block = uses[i]; i++) {
|
||||
if (block.type == 'procedures_defnoreturn' ||
|
||||
block.type == 'procedures_defreturn') {
|
||||
var procedureName = block.getFieldValue('NAME');
|
||||
Blockly.alert(
|
||||
Blockly.Msg.CANNOT_DELETE_VARIABLE_PROCEDURE.
|
||||
replace('%1', name).
|
||||
replace('%2', procedureName));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var workspace = this;
|
||||
var variable = workspace.getVariable(name, type);
|
||||
if (uses.length > 1) {
|
||||
// Confirm before deleting multiple blocks.
|
||||
Blockly.confirm(
|
||||
Blockly.Msg.DELETE_VARIABLE_CONFIRMATION.replace('%1',
|
||||
String(uses.length)).
|
||||
replace('%2', name),
|
||||
function(ok) {
|
||||
if (ok) {
|
||||
workspace.deleteVariableInternal_(variable);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// No confirmation necessary for a single block.
|
||||
this.deleteVariableInternal_(variable);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete a variables by the passed in ID and all of its uses from this
|
||||
* workspace. May prompt the user for confirmation.
|
||||
@@ -394,7 +272,37 @@ Blockly.Workspace.prototype.deleteVariable = function(name, opt_type) {
|
||||
Blockly.Workspace.prototype.deleteVariableById = function(id) {
|
||||
var variable = this.getVariableById(id);
|
||||
if (variable) {
|
||||
this.deleteVariableInternal_(variable);
|
||||
// Check whether this variable is a function parameter before deleting.
|
||||
var variableName = variable.name;
|
||||
var uses = this.getVariableUsesById(id);
|
||||
for (var i = 0, block; block = uses[i]; i++) {
|
||||
if (block.type == 'procedures_defnoreturn' ||
|
||||
block.type == 'procedures_defreturn') {
|
||||
var procedureName = block.getFieldValue('NAME');
|
||||
var deleteText = Blockly.Msg.CANNOT_DELETE_VARIABLE_PROCEDURE.
|
||||
replace('%1', variableName).
|
||||
replace('%2', procedureName);
|
||||
Blockly.alert(deleteText);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var workspace = this;
|
||||
if (uses.length > 1) {
|
||||
// Confirm before deleting multiple blocks.
|
||||
var confirmText = Blockly.Msg.DELETE_VARIABLE_CONFIRMATION.
|
||||
replace('%1', String(uses.length)).
|
||||
replace('%2', variableName);
|
||||
Blockly.confirm(confirmText,
|
||||
function(ok) {
|
||||
if (ok) {
|
||||
workspace.deleteVariableInternal_(variable, uses);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// No confirmation necessary for a single block.
|
||||
this.deleteVariableInternal_(variable, uses);
|
||||
}
|
||||
} else {
|
||||
console.warn("Can't delete non-existent variable: " + id);
|
||||
}
|
||||
@@ -404,10 +312,10 @@ Blockly.Workspace.prototype.deleteVariableById = function(id) {
|
||||
* Deletes a variable and all of its uses from this workspace without asking the
|
||||
* user for confirmation.
|
||||
* @param {!Blockly.VariableModel} variable Variable to delete.
|
||||
* @param {!Array.<!Blockly.Block>} uses An array of uses of the variable.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Workspace.prototype.deleteVariableInternal_ = function(variable) {
|
||||
var uses = this.getVariableUses(variable.name);
|
||||
Blockly.Workspace.prototype.deleteVariableInternal_ = function(variable, uses) {
|
||||
Blockly.Events.setGroup(true);
|
||||
for (var i = 0; i < uses.length; i++) {
|
||||
uses[i].dispose(true, false);
|
||||
@@ -621,6 +529,25 @@ Blockly.Workspace.prototype.getAllVariables = function() {
|
||||
return this.variableMap_.getAllVariables();
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the variable map that contains "potential" variables. These exist in
|
||||
* the flyout but not in the workspace.
|
||||
* @return {?Blockly.VariableMap} The potential variable map.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Workspace.prototype.getPotentialVariableMap = function() {
|
||||
return this.isFlyout ? this.potentialVariableMap_ : null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the map of all variables on the workspace.
|
||||
* @return {?Blockly.VariableMap} The variable map.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Workspace.prototype.getVariableMap = function() {
|
||||
return this.variableMap_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Database of all workspaces.
|
||||
* @private
|
||||
|
||||
103
core/xml.js
103
core/xml.js
@@ -86,6 +86,30 @@ Blockly.Xml.blockToDomWithXY = function(block, opt_noId) {
|
||||
return element;
|
||||
};
|
||||
|
||||
Blockly.Xml.fieldToDomVariable_ = function(field, workspace) {
|
||||
var id = field.getValue();
|
||||
var variable = workspace.getVariableById(id);
|
||||
if (!variable) {
|
||||
if (workspace.isFlyout && workspace.targetWorkspace) {
|
||||
var potentialVariableMap = workspace.getPotentialVariableMap();
|
||||
if (potentialVariableMap) {
|
||||
variable = potentialVariableMap.getVariableById(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (variable) {
|
||||
var container = goog.dom.createDom('field', null, variable.name);
|
||||
container.setAttribute('name', field.name);
|
||||
container.setAttribute('id', variable.getId());
|
||||
container.setAttribute('variabletype', variable.type);
|
||||
return container;
|
||||
} else {
|
||||
// something went wrong?
|
||||
console.warn('no variable in fieldtodom');
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a field as XML.
|
||||
* @param {!Blockly.Field} field The field to encode.
|
||||
@@ -96,16 +120,13 @@ Blockly.Xml.blockToDomWithXY = function(block, opt_noId) {
|
||||
*/
|
||||
Blockly.Xml.fieldToDom_ = function(field, workspace) {
|
||||
if (field.name && field.EDITABLE) {
|
||||
var container = goog.dom.createDom('field', null, field.getValue());
|
||||
container.setAttribute('name', field.name);
|
||||
if (field instanceof Blockly.FieldVariable) {
|
||||
var variable = workspace.getVariable(field.getValue());
|
||||
if (variable) {
|
||||
container.setAttribute('id', variable.getId());
|
||||
container.setAttribute('variabletype', variable.type);
|
||||
}
|
||||
return Blockly.Xml.fieldToDomVariable_(field, workspace);
|
||||
} else {
|
||||
var container = goog.dom.createDom('field', null, field.getValue());
|
||||
container.setAttribute('name', field.name);
|
||||
return container;
|
||||
}
|
||||
return container;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
@@ -397,7 +418,6 @@ Blockly.Xml.domToWorkspace = function(xml, workspace) {
|
||||
}
|
||||
Blockly.Field.stopCache();
|
||||
}
|
||||
workspace.updateVariableStore(false);
|
||||
// Re-enable workspace resizing.
|
||||
if (workspace.setResizesEnabled) {
|
||||
workspace.setResizesEnabled(true);
|
||||
@@ -476,9 +496,11 @@ Blockly.Xml.domToBlock = function(xmlBlock, workspace) {
|
||||
}
|
||||
// Create top-level block.
|
||||
Blockly.Events.disable();
|
||||
var variablesBeforeCreation = workspace.getAllVariables();
|
||||
try {
|
||||
var topBlock = Blockly.Xml.domToBlockHeadless_(xmlBlock, workspace);
|
||||
if (workspace.rendered) {
|
||||
// TODO (fenichel): Otherwise call initModel?
|
||||
// Hide connections to speed up assembly.
|
||||
topBlock.setConnectionsHidden(true);
|
||||
// Generate list of all blocks.
|
||||
@@ -507,6 +529,13 @@ Blockly.Xml.domToBlock = function(xmlBlock, workspace) {
|
||||
}
|
||||
if (Blockly.Events.isEnabled()) {
|
||||
Blockly.Events.fire(new Blockly.Events.BlockCreate(topBlock));
|
||||
var newVariables = Blockly.Variables.getAddedVariables(workspace,
|
||||
variablesBeforeCreation);
|
||||
// Fire a VarCreate event for each (if any) new variable created.
|
||||
for(var i = 0; i < newVariables.length; i++) {
|
||||
var thisVariable = newVariables[i];
|
||||
Blockly.Events.fire(new Blockly.Events.VarCreate(thisVariable));
|
||||
}
|
||||
}
|
||||
return topBlock;
|
||||
};
|
||||
@@ -698,6 +727,37 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) {
|
||||
return block;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode an XML variable field tag and set the value of that field.
|
||||
* @param {!Blockly.Workspace} workspace The workspace that is currently being
|
||||
* deserialized.
|
||||
* @param {!Element} xml The field tag to decode.
|
||||
* @param {string} text The text content of the XML tag.
|
||||
* @param {!Blockly.FieldVariable} field The field on which the value will be
|
||||
* set.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Xml.domToFieldVariable_ = function(workspace, xml, text, field) {
|
||||
var type = xml.getAttribute('variabletype') || '';
|
||||
// TODO (fenichel): Does this need to be explicit or not?
|
||||
if (type == '\'\'') {
|
||||
type = '';
|
||||
}
|
||||
|
||||
var variable =
|
||||
Blockly.Variables.getOrCreateVariable(workspace, xml.id, text, type);
|
||||
|
||||
// This should never happen :)
|
||||
if (type != null && type !== variable.type) {
|
||||
throw Error('Serialized variable type with id \'' +
|
||||
variable.getId() + '\' had type ' + variable.type + ', and ' +
|
||||
'does not match variable field that references it: ' +
|
||||
Blockly.Xml.domToText(xml) + '.');
|
||||
}
|
||||
|
||||
field.setValue(variable.getId());
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode an XML field tag and set the value of that field on the given block.
|
||||
* @param {!Blockly.Block} block The block that is currently being deserialized.
|
||||
@@ -716,29 +776,10 @@ Blockly.Xml.domToField_ = function(block, fieldName, xml) {
|
||||
var workspace = block.workspace;
|
||||
var text = xml.textContent;
|
||||
if (field instanceof Blockly.FieldVariable) {
|
||||
// TODO (#1199): When we change setValue and getValue to
|
||||
// interact with IDs instead of names, update this so that we get
|
||||
// the variable based on ID instead of textContent.
|
||||
var type = xml.getAttribute('variabletype') || '';
|
||||
// TODO: Consider using a different name (varID?) because this is the
|
||||
// node's ID.
|
||||
var id = xml.id;
|
||||
if (id) {
|
||||
var variable = workspace.getVariableById(id);
|
||||
} else {
|
||||
var variable = workspace.getVariable(text, type);
|
||||
}
|
||||
if (!variable) {
|
||||
variable = workspace.createVariable(text, type, id);
|
||||
}
|
||||
if (type != null && type !== variable.type) {
|
||||
throw Error('Serialized variable type with id \'' +
|
||||
variable.getId() + '\' had type ' + variable.type + ', and ' +
|
||||
'does not match variable field that references it: ' +
|
||||
Blockly.Xml.domToText(xml) + '.');
|
||||
}
|
||||
Blockly.Xml.domToFieldVariable_(workspace, xml, text, field);
|
||||
} else {
|
||||
field.setValue(text);
|
||||
}
|
||||
field.setValue(text);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -44,10 +44,20 @@ function fieldVariable_mockBlock(workspace) {
|
||||
return {'workspace': workspace, 'isShadow': function(){return false;}};
|
||||
}
|
||||
|
||||
function fieldVariable_createAndInitField(workspace) {
|
||||
var fieldVariable = new Blockly.FieldVariable('name1');
|
||||
var mockBlock = fieldVariable_mockBlock(workspace);
|
||||
fieldVariable.setSourceBlock(mockBlock);
|
||||
// No view to initialize, but the model still needs work.
|
||||
fieldVariable.initModel();
|
||||
return fieldVariable;
|
||||
}
|
||||
|
||||
function test_fieldVariable_Constructor() {
|
||||
workspace = new Blockly.Workspace();
|
||||
var fieldVariable = new Blockly.FieldVariable('name1');
|
||||
assertEquals('name1', fieldVariable.getText());
|
||||
// The field does not have a variable until after init() is called.
|
||||
assertEquals('', fieldVariable.getText());
|
||||
workspace.dispose();
|
||||
}
|
||||
|
||||
@@ -55,52 +65,38 @@ function test_fieldVariable_setValueMatchId() {
|
||||
// Expect the fieldVariable value to be set to variable name
|
||||
fieldVariableTestWithMocks_setUp();
|
||||
workspace.createVariable('name2', null, 'id2');
|
||||
var fieldVariable = new Blockly.FieldVariable('name1');
|
||||
var mockBlock = fieldVariable_mockBlock(workspace);
|
||||
fieldVariable.setSourceBlock(mockBlock);
|
||||
|
||||
var fieldVariable = fieldVariable_createAndInitField(workspace);
|
||||
|
||||
var oldId = fieldVariable.getValue();
|
||||
var event = new Blockly.Events.BlockChange(
|
||||
mockBlock, 'field', undefined, 'name1', 'id2');
|
||||
fieldVariable.sourceBlock_, 'field', undefined, oldId, 'id2');
|
||||
setUpMockMethod(mockControl_, Blockly.Events, 'fire', [event], null);
|
||||
|
||||
fieldVariable.setValue('id2');
|
||||
assertEquals('name2', fieldVariable.getText());
|
||||
assertEquals('id2', fieldVariable.value_);
|
||||
fieldVariableTestWithMocks_tearDown();
|
||||
}
|
||||
|
||||
function test_fieldVariable_setValueMatchName() {
|
||||
// Expect the fieldVariable value to be set to variable name
|
||||
fieldVariableTestWithMocks_setUp();
|
||||
workspace.createVariable('name2', null, 'id2');
|
||||
var fieldVariable = new Blockly.FieldVariable('name1');
|
||||
var mockBlock = fieldVariable_mockBlock(workspace);
|
||||
fieldVariable.setSourceBlock(mockBlock);
|
||||
var event = new Blockly.Events.BlockChange(
|
||||
mockBlock, 'field', undefined, 'name1', 'id2');
|
||||
setUpMockMethod(mockControl_, Blockly.Events, 'fire', [event], null);
|
||||
|
||||
fieldVariable.setValue('name2');
|
||||
assertEquals('name2', fieldVariable.getText());
|
||||
assertEquals('id2', fieldVariable.value_);
|
||||
assertEquals('id2', fieldVariable.getValue());
|
||||
fieldVariableTestWithMocks_tearDown();
|
||||
}
|
||||
|
||||
function test_fieldVariable_setValueNoVariable() {
|
||||
// Expect the fieldVariable value to be set to the passed in string. No error
|
||||
// should be thrown.
|
||||
fieldVariableTestWithMocks_setUp();
|
||||
var fieldVariable = new Blockly.FieldVariable('name1');
|
||||
var mockBlock = {'workspace': workspace,
|
||||
'isShadow': function(){return false;}};
|
||||
fieldVariable.setSourceBlock(mockBlock);
|
||||
var event = new Blockly.Events.BlockChange(
|
||||
mockBlock, 'field', undefined, 'name1', 'id1');
|
||||
setUpMockMethod(mockControl_, Blockly.Events, 'fire', [event], null);
|
||||
|
||||
fieldVariable.setValue('id1');
|
||||
assertEquals('id1', fieldVariable.getText());
|
||||
assertEquals('id1', fieldVariable.value_);
|
||||
fieldVariableTestWithMocks_tearDown();
|
||||
var fieldVariable = fieldVariable_createAndInitField(workspace);
|
||||
var mockBlock = fieldVariable.sourceBlock_;
|
||||
mockBlock.isShadow = function() {
|
||||
return false;
|
||||
};
|
||||
|
||||
try {
|
||||
fieldVariable.setValue('id1');
|
||||
// Calling setValue with a variable that doesn't exist throws an error.
|
||||
fail();
|
||||
} catch (e) {
|
||||
// expected
|
||||
} finally {
|
||||
fieldVariableTestWithMocks_tearDown();
|
||||
}
|
||||
}
|
||||
|
||||
function test_fieldVariable_dropdownCreateVariablesExist() {
|
||||
@@ -108,12 +104,12 @@ function test_fieldVariable_dropdownCreateVariablesExist() {
|
||||
workspace = new Blockly.Workspace();
|
||||
workspace.createVariable('name1', '', 'id1');
|
||||
workspace.createVariable('name2', '', 'id2');
|
||||
|
||||
var fieldVariable = fieldVariable_createAndInitField(workspace);
|
||||
|
||||
var result_options = Blockly.FieldVariable.dropdownCreate.call(
|
||||
{
|
||||
'sourceBlock_': {'workspace': workspace},
|
||||
'getText': function(){return 'name1';},
|
||||
'getVariableTypes_': function(){return [''];}
|
||||
});
|
||||
fieldVariable);
|
||||
|
||||
assertEquals(result_options.length, 3);
|
||||
isEqualArrays(result_options[0], ['name1', 'id1']);
|
||||
isEqualArrays(result_options[1], ['name2', 'id2']);
|
||||
@@ -121,77 +117,30 @@ function test_fieldVariable_dropdownCreateVariablesExist() {
|
||||
workspace.dispose();
|
||||
}
|
||||
|
||||
function test_fieldVariable_dropdownCreateVariablesExist() {
|
||||
// Expect that the dropdown options will contain the variables that exist.
|
||||
workspace = new Blockly.Workspace();
|
||||
workspace.createVariable('name1', '', 'id1');
|
||||
workspace.createVariable('name2', '', 'id2');
|
||||
var result_options = Blockly.FieldVariable.dropdownCreate.call(
|
||||
{
|
||||
'sourceBlock_': {'workspace': workspace},
|
||||
'getText': function(){return 'name1';},
|
||||
'getVariableTypes_': function(){return [''];}
|
||||
});
|
||||
assertEquals(result_options.length, 3);
|
||||
isEqualArrays(result_options[0], ['name1', 'id1']);
|
||||
isEqualArrays(result_options[1], ['name2', 'id2']);
|
||||
|
||||
workspace.dispose();
|
||||
}
|
||||
|
||||
function test_fieldVariable_dropdownVariableAndTypeDoesNotExist() {
|
||||
// Expect a variable will be created for the selected option. Expect the
|
||||
// workspace variable map to contain the new variable once.
|
||||
function test_fieldVariable_setValueNull() {
|
||||
// This should no longer create a variable for the selected option.
|
||||
fieldVariableTestWithMocks_setUp();
|
||||
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['id1', null]);
|
||||
|
||||
var result_options = Blockly.FieldVariable.dropdownCreate.call(
|
||||
{
|
||||
'sourceBlock_': {'workspace': workspace},
|
||||
'getText': function(){return 'name1';},
|
||||
'getVariableTypes_': function(){return [''];}
|
||||
});
|
||||
var fieldVariable = fieldVariable_createAndInitField(workspace);
|
||||
try {
|
||||
fieldVariable.setValue(null);
|
||||
fail();
|
||||
} catch (e) {
|
||||
// expected
|
||||
} finally {
|
||||
fieldVariableTestWithMocks_tearDown();
|
||||
}
|
||||
|
||||
// Check the options.
|
||||
assertEquals(2, result_options.length);
|
||||
isEqualArrays(result_options[0], ['name1', 'id1']);
|
||||
// Check the variable map.
|
||||
assertEquals(1, workspace.getAllVariables().length);
|
||||
checkVariableValues(workspace, 'name1', '', 'id1');
|
||||
|
||||
fieldVariableTestWithMocks_tearDown();
|
||||
}
|
||||
|
||||
function test_fieldVariable_dropdownVariableDoesNotExistTypeDoes() {
|
||||
// Expect a variable will be created for the selected option. Expect the
|
||||
// workspace variable map to contain the new variable once.
|
||||
fieldVariableTestWithMocks_setUp();
|
||||
workspace.createVariable('name1', '', 'id1');
|
||||
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['id2', null]);
|
||||
|
||||
var result_options = Blockly.FieldVariable.dropdownCreate.call(
|
||||
{
|
||||
'sourceBlock_': {'workspace': workspace},
|
||||
'getText': function(){return 'name2';},
|
||||
'getVariableTypes_': function(){return [''];}
|
||||
});
|
||||
|
||||
assertEquals(3, result_options.length);
|
||||
isEqualArrays(result_options[0], ['name1', 'id1']);
|
||||
isEqualArrays(result_options[1], ['name2', 'id2']);
|
||||
assertEquals(2, workspace.variableMap_.getAllVariables().length);
|
||||
checkVariableValues(workspace, 'name1', '', 'id1');
|
||||
checkVariableValues(workspace, 'name2', '', 'id2');
|
||||
|
||||
fieldVariableTestWithMocks_tearDown();
|
||||
}
|
||||
|
||||
function test_fieldVariable_getVariableTypes_undefinedVariableTypes() {
|
||||
// Expect that since variableTypes is undefined, only type empty string
|
||||
// will be returned.
|
||||
// will be returned (regardless of what types are available on the workspace).
|
||||
workspace = new Blockly.Workspace();
|
||||
workspace.createVariable('name1', 'type1');
|
||||
workspace.createVariable('name2', 'type2');
|
||||
|
||||
var fieldVariable = new Blockly.FieldVariable('name1');
|
||||
var resultTypes = fieldVariable.getVariableTypes_();
|
||||
isEqualArrays(resultTypes, ['']);
|
||||
@@ -199,12 +148,14 @@ function test_fieldVariable_getVariableTypes_undefinedVariableTypes() {
|
||||
}
|
||||
|
||||
function test_fieldVariable_getVariableTypes_givenVariableTypes() {
|
||||
// Expect that since variableTypes is undefined, only type empty string
|
||||
// will be returned.
|
||||
// Expect that since variableTypes is defined, it will be the return value,
|
||||
// regardless of what types are available on the workspace.
|
||||
workspace = new Blockly.Workspace();
|
||||
workspace.createVariable('name1', 'type1');
|
||||
workspace.createVariable('name2', 'type2');
|
||||
var fieldVariable = new Blockly.FieldVariable('name1', null, ['type1', 'type2']);
|
||||
|
||||
var fieldVariable = new Blockly.FieldVariable(
|
||||
'name1', null, ['type1', 'type2']);
|
||||
var resultTypes = fieldVariable.getVariableTypes_();
|
||||
isEqualArrays(resultTypes, ['type1', 'type2']);
|
||||
workspace.dispose();
|
||||
@@ -212,13 +163,17 @@ function test_fieldVariable_getVariableTypes_givenVariableTypes() {
|
||||
|
||||
function test_fieldVariable_getVariableTypes_nullVariableTypes() {
|
||||
// Expect all variable types to be returned.
|
||||
// The variable does not need to be initialized to do this--it just needs a
|
||||
// pointer to the workspace.
|
||||
workspace = new Blockly.Workspace();
|
||||
workspace.createVariable('name1', 'type1');
|
||||
workspace.createVariable('name2', 'type2');
|
||||
|
||||
var fieldVariable = new Blockly.FieldVariable('name1');
|
||||
var mockBlock = fieldVariable_mockBlock(workspace);
|
||||
fieldVariable.setSourceBlock(mockBlock);
|
||||
fieldVariable.variableTypes = null;
|
||||
|
||||
var resultTypes = fieldVariable.getVariableTypes_();
|
||||
isEqualArrays(resultTypes, ['type1', 'type2']);
|
||||
workspace.dispose();
|
||||
@@ -229,12 +184,15 @@ function test_fieldVariable_getVariableTypes_emptyListVariableTypes() {
|
||||
workspace = new Blockly.Workspace();
|
||||
workspace.createVariable('name1', 'type1');
|
||||
workspace.createVariable('name2', 'type2');
|
||||
|
||||
var fieldVariable = new Blockly.FieldVariable('name1');
|
||||
var mockBlock = fieldVariable_mockBlock(workspace);
|
||||
fieldVariable.setSourceBlock(mockBlock);
|
||||
fieldVariable.variableTypes = [];
|
||||
|
||||
try {
|
||||
fieldVariable.getVariableTypes_();
|
||||
fail();
|
||||
} catch (e) {
|
||||
//expected
|
||||
} finally {
|
||||
|
||||
@@ -41,10 +41,10 @@ function proceduresTest_setUpWithMockBlocks() {
|
||||
'name': 'NAME',
|
||||
'variable': 'item'
|
||||
}
|
||||
],
|
||||
]
|
||||
}]);
|
||||
Blockly.Blocks['procedure_mock_block'].getProcedureDef = function() {
|
||||
return [this.getFieldValue('NAME'), [], false];
|
||||
return [this.getField('NAME').getText(), [], false];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -63,8 +63,9 @@ function test_isNameUsed_NoBlocks() {
|
||||
|
||||
function test_isNameUsed_False() {
|
||||
proceduresTest_setUpWithMockBlocks();
|
||||
workspace.createVariable('name2', '', 'id2');
|
||||
var block = new Blockly.Block(workspace, 'procedure_mock_block');
|
||||
block.setFieldValue('name2', 'NAME');
|
||||
block.setFieldValue('id2', 'NAME');
|
||||
|
||||
var result = Blockly.Procedures.isNameUsed('name1', workspace);
|
||||
assertFalse(result);
|
||||
@@ -73,8 +74,9 @@ function test_isNameUsed_False() {
|
||||
|
||||
function test_isNameUsed_True() {
|
||||
proceduresTest_setUpWithMockBlocks();
|
||||
workspace.createVariable('name1', '', 'id1');
|
||||
var block = new Blockly.Block(workspace, 'procedure_mock_block');
|
||||
block.setFieldValue('name1', 'NAME');
|
||||
block.setFieldValue('id1', 'NAME');
|
||||
|
||||
var result = Blockly.Procedures.isNameUsed('name1', workspace);
|
||||
assertTrue(result);
|
||||
|
||||
@@ -89,3 +89,54 @@ function checkVariableValues(container, name, type, id) {
|
||||
assertEquals(type, variable.type);
|
||||
assertEquals(id, variable.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a test get_var_block.
|
||||
* Will fail if get_var_block isn't defined.
|
||||
* TODO (fenichel): Rename to createMockVarBlock.
|
||||
* @param {!string} variable_id The id of the variable to reference.
|
||||
* @return {!Blockly.Block} The created block.
|
||||
*/
|
||||
function createMockBlock(variable_id) {
|
||||
if (!Blockly.Blocks['get_var_block']) {
|
||||
fail();
|
||||
}
|
||||
// Turn off events to avoid testing XML at the same time.
|
||||
Blockly.Events.disable();
|
||||
var block = new Blockly.Block(workspace, 'get_var_block');
|
||||
block.inputList[0].fieldRow[0].setValue(variable_id);
|
||||
Blockly.Events.enable();
|
||||
return block;
|
||||
}
|
||||
|
||||
function createTwoVariablesAndBlocks(workspace) {
|
||||
// Create two variables of different types.
|
||||
workspace.createVariable('name1', 'type1', 'id1');
|
||||
workspace.createVariable('name2', 'type2', 'id2');
|
||||
// Create blocks to refer to both of them.
|
||||
createMockBlock('id1');
|
||||
createMockBlock('id2');
|
||||
}
|
||||
|
||||
function createVariableAndBlock(workspace) {
|
||||
workspace.createVariable('name1', 'type1', 'id1');
|
||||
createMockBlock('id1');
|
||||
}
|
||||
|
||||
function defineGetVarBlock() {
|
||||
Blockly.defineBlocksWithJsonArray([{
|
||||
"type": "get_var_block",
|
||||
"message0": "%1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_variable",
|
||||
"name": "VAR",
|
||||
"variableTypes": ["", "type1", "type2"]
|
||||
}
|
||||
]
|
||||
}]);
|
||||
}
|
||||
|
||||
function undefineGetVarBlock() {
|
||||
delete Blockly.Blocks['get_var_block'];
|
||||
}
|
||||
|
||||
@@ -24,38 +24,19 @@ goog.require('goog.testing.MockControl');
|
||||
|
||||
var workspace;
|
||||
var mockControl_;
|
||||
Blockly.defineBlocksWithJsonArray([{
|
||||
"type": "get_var_block",
|
||||
"message0": "%1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_variable",
|
||||
"name": "VAR",
|
||||
}
|
||||
]
|
||||
}]);
|
||||
|
||||
function workspaceTest_setUp() {
|
||||
defineGetVarBlock();
|
||||
workspace = new Blockly.Workspace();
|
||||
mockControl_ = new goog.testing.MockControl();
|
||||
}
|
||||
|
||||
function workspaceTest_tearDown() {
|
||||
undefineGetVarBlock();
|
||||
mockControl_.$tearDown();
|
||||
workspace.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a test get_var_block.
|
||||
* @param {?string} variable_name The string to put into the variable field.
|
||||
* @return {!Blockly.Block} The created block.
|
||||
*/
|
||||
function createMockBlock(variable_name) {
|
||||
var block = new Blockly.Block(workspace, 'get_var_block');
|
||||
block.inputList[0].fieldRow[0].setValue(variable_name);
|
||||
return block;
|
||||
}
|
||||
|
||||
function test_emptyWorkspace() {
|
||||
workspaceTest_setUp();
|
||||
try {
|
||||
@@ -158,107 +139,43 @@ function test_getBlockById() {
|
||||
|
||||
function test_deleteVariable_InternalTrivial() {
|
||||
workspaceTest_setUp();
|
||||
// TODO (#1199): make a similar test where the variable is given a non-empty
|
||||
// type.
|
||||
var var_1 = workspace.createVariable('name1', '', 'id1');
|
||||
workspace.createVariable('name2', '', 'id2');
|
||||
createMockBlock('name1');
|
||||
createMockBlock('name1');
|
||||
createMockBlock('name2');
|
||||
var var_1 = workspace.createVariable('name1', 'type1', 'id1');
|
||||
workspace.createVariable('name2', 'type2', 'id2');
|
||||
createMockBlock('id1');
|
||||
createMockBlock('id1');
|
||||
createMockBlock('id2');
|
||||
|
||||
workspace.deleteVariableInternal_(var_1);
|
||||
var variable = workspace.getVariable('name1', '');
|
||||
var block_var_name = workspace.topBlocks_[0].getVars()[0];
|
||||
var uses = workspace.getVariableUsesById(var_1.getId());
|
||||
workspace.deleteVariableInternal_(var_1, uses);
|
||||
|
||||
var variable = workspace.getVariableById('id1');
|
||||
var block_var_name = workspace.topBlocks_[0].getVarModels()[0].name;
|
||||
assertNull(variable);
|
||||
checkVariableValues(workspace, 'name2', '', 'id2');
|
||||
checkVariableValues(workspace, 'name2', 'type2', 'id2');
|
||||
assertEquals('name2', block_var_name);
|
||||
workspaceTest_tearDown();
|
||||
}
|
||||
|
||||
// TODO(marisaleung): Test the alert for deleting a variable that is a procedure.
|
||||
|
||||
function test_updateVariableStore_TrivialNoClear() {
|
||||
workspaceTest_setUp();
|
||||
workspace.createVariable('name1', 'type1', 'id1');
|
||||
workspace.createVariable('name2', 'type2', 'id2');
|
||||
setUpMockMethod(mockControl_, Blockly.Variables, 'allUsedVariables',
|
||||
[workspace], [['name1', 'name2']]);
|
||||
|
||||
try {
|
||||
workspace.updateVariableStore();
|
||||
checkVariableValues(workspace, 'name1', 'type1', 'id1');
|
||||
checkVariableValues(workspace, 'name2', 'type2', 'id2');
|
||||
} finally {
|
||||
workspaceTest_tearDown();
|
||||
}
|
||||
}
|
||||
|
||||
function test_updateVariableStore_NameNotInvariableMap_NoClear() {
|
||||
workspaceTest_setUp();
|
||||
setUpMockMethod(mockControl_, Blockly.Variables, 'allUsedVariables',
|
||||
[workspace], [['name1']]);
|
||||
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']);
|
||||
|
||||
try {
|
||||
workspace.updateVariableStore();
|
||||
checkVariableValues(workspace, 'name1', '', '1');
|
||||
} finally {
|
||||
workspaceTest_tearDown();
|
||||
}
|
||||
}
|
||||
|
||||
function test_updateVariableStore_ClearAndAllInUse() {
|
||||
workspaceTest_setUp();
|
||||
workspace.createVariable('name1', '', 'id1');
|
||||
workspace.createVariable('name2', '', 'id2');
|
||||
// TODO (#1199): make a similar test where the variable is given a non-empty
|
||||
// type.
|
||||
// TODO (#1199): get rid of updateVariableStore if possible.
|
||||
setUpMockMethod(mockControl_, Blockly.Variables, 'allUsedVariables',
|
||||
[workspace], [['name1', 'name2']]);
|
||||
|
||||
try {
|
||||
workspace.updateVariableStore(true);
|
||||
checkVariableValues(workspace, 'name1', '', 'id1');
|
||||
checkVariableValues(workspace, 'name2', '', 'id2');
|
||||
} finally {
|
||||
workspaceTest_tearDown();
|
||||
}
|
||||
}
|
||||
|
||||
function test_updateVariableStore_ClearAndOneInUse() {
|
||||
workspaceTest_setUp();
|
||||
workspace.createVariable('name1', '', 'id1');
|
||||
workspace.createVariable('name2', '', 'id2');
|
||||
// TODO (#1199): make a similar test where the variable is given a non-empty
|
||||
// type.
|
||||
// TODO (#1199): get rid of updateVariableStore if possible.
|
||||
setUpMockMethod(mockControl_, Blockly.Variables, 'allUsedVariables',
|
||||
[workspace], [['name1']]);
|
||||
|
||||
try {
|
||||
workspace.updateVariableStore(true);
|
||||
checkVariableValues(workspace, 'name1', '', 'id1');
|
||||
var variabe = workspace.getVariable('name2', '');
|
||||
assertNull(variable);
|
||||
} finally {
|
||||
workspaceTest_tearDown();
|
||||
}
|
||||
}
|
||||
|
||||
function test_addTopBlock_TrivialFlyoutIsTrue() {
|
||||
workspaceTest_setUp();
|
||||
workspace.isFlyout = true;
|
||||
var block = createMockBlock();
|
||||
workspace.removeTopBlock(block);
|
||||
setUpMockMethod(mockControl_, Blockly.Variables, 'allUsedVariables', [block],
|
||||
[['name1']]);
|
||||
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']);
|
||||
var targetWorkspace = new Blockly.Workspace();
|
||||
workspace.targetWorkspace = targetWorkspace;
|
||||
targetWorkspace.createVariable('name1', '', '1');
|
||||
|
||||
// Flyout.init usually does this binding.
|
||||
workspace.getVariableById =
|
||||
targetWorkspace.getVariableById.bind(targetWorkspace);
|
||||
|
||||
try {
|
||||
var block = createMockBlock('1');
|
||||
workspace.removeTopBlock(block);
|
||||
workspace.addTopBlock(block);
|
||||
checkVariableValues(workspace, 'name1', '', '1');
|
||||
} finally {
|
||||
targetWorkspace.dispose();
|
||||
workspaceTest_tearDown();
|
||||
}
|
||||
}
|
||||
@@ -297,52 +214,38 @@ function test_clear_NoVariables() {
|
||||
}
|
||||
}
|
||||
|
||||
function test_renameVariable_NoBlocks() {
|
||||
// Expect 'renameVariable' to create new variable with newName.
|
||||
function test_renameVariable_NoReference() {
|
||||
// Test renaming a variable in the simplest case: when no blocks refer to it.
|
||||
workspaceTest_setUp();
|
||||
var id = 'id1';
|
||||
var type = 'type1';
|
||||
var oldName = 'name1';
|
||||
var newName = 'name2';
|
||||
// Mocked setGroup to ensure only one call to the mocked genUid.
|
||||
setUpMockMethod(mockControl_, Blockly.Events, 'setGroup', [true, false],
|
||||
null);
|
||||
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']);
|
||||
workspace.createVariable(oldName, type, id);
|
||||
|
||||
try {
|
||||
workspace.renameVariable(oldName, newName);
|
||||
checkVariableValues(workspace, 'name2', '', '1');
|
||||
var variable = workspace.getVariable(oldName, '');
|
||||
assertNull(variable);
|
||||
workspace.renameVariableById(id, newName);
|
||||
checkVariableValues(workspace, newName, type, id);
|
||||
// Renaming should not have created a new variable.
|
||||
assertEquals(1, workspace.getAllVariables().length);
|
||||
} finally {
|
||||
workspaceTest_tearDown();
|
||||
}
|
||||
}
|
||||
|
||||
function test_renameVariable_SameNameNoBlocks() {
|
||||
// Expect 'renameVariable' to create new variable with newName.
|
||||
workspaceTest_setUp();
|
||||
var name = 'name1';
|
||||
workspace.createVariable(name, 'type1', 'id1');
|
||||
|
||||
workspace.renameVariable(name, name);
|
||||
checkVariableValues(workspace, name, 'type1', 'id1');
|
||||
workspaceTest_tearDown();
|
||||
}
|
||||
|
||||
function test_renameVariable_OnlyOldNameBlockExists() {
|
||||
function test_renameVariable_ReferenceExists() {
|
||||
// Test renaming a variable when a reference to it exists.
|
||||
// Expect 'renameVariable' to change oldName variable name to newName.
|
||||
workspaceTest_setUp();
|
||||
var oldName = 'name1';
|
||||
var newName = 'name2';
|
||||
workspace.createVariable(oldName, '', 'id1');
|
||||
createMockBlock(oldName);
|
||||
|
||||
// TODO (#1199): make a similar test where the variable is given a non-empty
|
||||
// type.
|
||||
workspace.renameVariable(oldName, newName);
|
||||
checkVariableValues(workspace, newName, '', 'id1');
|
||||
var variable = workspace.getVariable(oldName, '');
|
||||
var block_var_name = workspace.topBlocks_[0].getVars()[0];
|
||||
assertNull(variable);
|
||||
createVariableAndBlock(workspace);
|
||||
|
||||
workspace.renameVariableById('id1', newName);
|
||||
checkVariableValues(workspace, newName, 'type1', 'id1');
|
||||
// Renaming should not have created a new variable.
|
||||
assertEquals(1, workspace.getAllVariables().length);
|
||||
var block_var_name = workspace.topBlocks_[0].getVarModels()[0].name;
|
||||
assertEquals(newName, block_var_name);
|
||||
workspaceTest_tearDown();
|
||||
}
|
||||
@@ -351,151 +254,120 @@ function test_renameVariable_TwoVariablesSameType() {
|
||||
// Expect 'renameVariable' to change oldName variable name to newName.
|
||||
// Expect oldName block name to change to newName
|
||||
workspaceTest_setUp();
|
||||
var id1 = 'id1';
|
||||
var id2 = 'id2';
|
||||
var type = 'type1';
|
||||
|
||||
var oldName = 'name1';
|
||||
var newName = 'name2';
|
||||
// TODO (#1199): make a similar test where the variable is given a non-empty
|
||||
// type.
|
||||
workspace.createVariable(oldName, '', 'id1');
|
||||
workspace.createVariable(newName, '', 'id2');
|
||||
createMockBlock(oldName);
|
||||
createMockBlock(newName);
|
||||
// Create two variables of the same type.
|
||||
workspace.createVariable(oldName, type, id1);
|
||||
workspace.createVariable(newName, type, id2);
|
||||
// Create blocks to refer to both of them.
|
||||
createMockBlock(id1);
|
||||
createMockBlock(id2);
|
||||
|
||||
workspace.renameVariable(oldName, newName);
|
||||
checkVariableValues(workspace, newName, '', 'id2');
|
||||
var variable = workspace.getVariable(oldName);
|
||||
var block_var_name_1 = workspace.topBlocks_[0].getVars()[0];
|
||||
var block_var_name_2 = workspace.topBlocks_[1].getVars()[0];
|
||||
workspace.renameVariableById(id1, newName);
|
||||
checkVariableValues(workspace, newName, type, id2);
|
||||
// The old variable should have been deleted.
|
||||
var variable = workspace.getVariableById(id1);
|
||||
assertNull(variable);
|
||||
|
||||
// There should only be one variable left.
|
||||
assertEquals(1, workspace.getAllVariables().length);
|
||||
|
||||
// References should have the correct names.
|
||||
var block_var_name_1 = workspace.topBlocks_[0].getVarModels()[0].name;
|
||||
var block_var_name_2 = workspace.topBlocks_[1].getVarModels()[0].name;
|
||||
assertEquals(newName, block_var_name_1);
|
||||
assertEquals(newName, block_var_name_2);
|
||||
|
||||
workspaceTest_tearDown();
|
||||
}
|
||||
|
||||
function test_renameVariable_TwoVariablesDifferentType() {
|
||||
// Expect triggered error because of different types
|
||||
// Expect the rename to succeed, because variables with different types are
|
||||
// allowed to have the same name.
|
||||
workspaceTest_setUp();
|
||||
var oldName = 'name1';
|
||||
var newName = 'name2';
|
||||
workspace.createVariable(oldName, 'type1', 'id1');
|
||||
workspace.createVariable(newName, 'type2', 'id2');
|
||||
createMockBlock(oldName);
|
||||
createMockBlock(newName);
|
||||
createTwoVariablesAndBlocks(workspace);
|
||||
|
||||
try {
|
||||
workspace.renameVariable(oldName, newName);
|
||||
fail();
|
||||
} catch (e) {
|
||||
// expected
|
||||
}
|
||||
checkVariableValues(workspace, oldName, 'type1', 'id1');
|
||||
var newName = 'name2';
|
||||
workspace.renameVariableById('id1', newName);
|
||||
|
||||
checkVariableValues(workspace, newName, 'type1', 'id1');
|
||||
checkVariableValues(workspace, newName, 'type2', 'id2');
|
||||
var block_var_name_1 = workspace.topBlocks_[0].getVars()[0];
|
||||
var block_var_name_2 = workspace.topBlocks_[1].getVars()[0];
|
||||
assertEquals(oldName, block_var_name_1);
|
||||
|
||||
// References shoul have the correct names.
|
||||
var block_var_name_1 = workspace.topBlocks_[0].getVarModels()[0].name;
|
||||
var block_var_name_2 = workspace.topBlocks_[1].getVarModels()[0].name;
|
||||
assertEquals(newName, block_var_name_1);
|
||||
assertEquals(newName, block_var_name_2);
|
||||
|
||||
workspaceTest_tearDown();
|
||||
}
|
||||
|
||||
function test_renameVariable_OldCase() {
|
||||
// Expect triggered error because of different types
|
||||
// Rename a variable with a single reference. Update only the capitalization.
|
||||
workspaceTest_setUp();
|
||||
var oldCase = 'Name1';
|
||||
var newName = 'name1';
|
||||
// TODO (#1199): make a similar test where the variable is given a non-empty
|
||||
// type.
|
||||
workspace.createVariable(oldCase, '', 'id1');
|
||||
createMockBlock(oldCase);
|
||||
var newName = 'Name1';
|
||||
|
||||
workspace.renameVariable(oldCase, newName);
|
||||
checkVariableValues(workspace, newName, '', 'id1');
|
||||
var result_oldCase = workspace.getVariable(oldCase, '').name;
|
||||
assertNotEquals(oldCase, result_oldCase);
|
||||
createVariableAndBlock(workspace);
|
||||
|
||||
workspace.renameVariableById('id1', newName);
|
||||
checkVariableValues(workspace, newName, 'type1', 'id1');
|
||||
var variable = workspace.getVariableById('id1');
|
||||
assertNotEquals('name1', variable.name);
|
||||
workspaceTest_tearDown();
|
||||
}
|
||||
|
||||
function test_renameVariable_TwoVariablesAndOldCase() {
|
||||
// Expect triggered error because of different types
|
||||
// Test renaming a variable to an in-use name, but with different
|
||||
// capitalization. The new capitalization should apply everywhere.
|
||||
|
||||
// TODO (fenichel): What about different capitalization but also different
|
||||
// types?
|
||||
workspaceTest_setUp();
|
||||
var oldName = 'name1';
|
||||
var oldCase = 'Name2';
|
||||
var newName = 'name2';
|
||||
// TODO (#1199): make a similar test where the variable is given a non-empty
|
||||
// type.
|
||||
workspace.createVariable(oldName, '', 'id1');
|
||||
workspace.createVariable(oldCase, '', 'id2');
|
||||
createMockBlock(oldName);
|
||||
createMockBlock(oldCase);
|
||||
|
||||
workspace.renameVariable(oldName, newName);
|
||||
var id1 = 'id1';
|
||||
var id2 = 'id2';
|
||||
|
||||
checkVariableValues(workspace, newName, '', 'id2');
|
||||
var variable = workspace.getVariable(oldName);
|
||||
var result_oldCase = workspace.getVariable(oldCase).name;
|
||||
var block_var_name_1 = workspace.topBlocks_[0].getVars()[0];
|
||||
var block_var_name_2 = workspace.topBlocks_[1].getVars()[0];
|
||||
var type = 'type1';
|
||||
|
||||
workspace.createVariable(oldName, type, id1);
|
||||
workspace.createVariable(oldCase, type, id2);
|
||||
createMockBlock(id1);
|
||||
createMockBlock(id2);
|
||||
|
||||
workspace.renameVariableById(id1, newName);
|
||||
|
||||
checkVariableValues(workspace, newName, type, id2);
|
||||
|
||||
// The old variable should have been deleted.
|
||||
var variable = workspace.getVariableById(id1);
|
||||
assertNull(variable);
|
||||
assertNotEquals(oldCase, result_oldCase);
|
||||
|
||||
// There should only be one variable left.
|
||||
assertEquals(1, workspace.getAllVariables().length);
|
||||
|
||||
// Blocks should now use the new capitalization.
|
||||
var block_var_name_1 = workspace.topBlocks_[0].getVarModels()[0].name;
|
||||
var block_var_name_2 = workspace.topBlocks_[1].getVarModels()[0].name;
|
||||
assertEquals(newName, block_var_name_1);
|
||||
assertEquals(newName, block_var_name_2);
|
||||
workspaceTest_tearDown();
|
||||
}
|
||||
|
||||
// Extra testing not required for renameVariableById. It calls renameVariable
|
||||
// and that has extensive testing.
|
||||
function test_renameVariableById_TwoVariablesSameType() {
|
||||
// Expect 'renameVariableById' to change oldName variable name to newName.
|
||||
// Expect oldName block name to change to newName
|
||||
workspaceTest_setUp();
|
||||
var oldName = 'name1';
|
||||
var newName = 'name2';
|
||||
// TODO (#1199): make a similar test where the variable is given a non-empty
|
||||
// type.
|
||||
workspace.createVariable(oldName, '', 'id1');
|
||||
workspace.createVariable(newName, '', 'id2');
|
||||
createMockBlock(oldName);
|
||||
createMockBlock(newName);
|
||||
|
||||
workspace.renameVariableById('id1', newName);
|
||||
checkVariableValues(workspace, newName, '', 'id2');
|
||||
var variable = workspace.getVariable(oldName);
|
||||
var block_var_name_1 = workspace.topBlocks_[0].getVars()[0];
|
||||
var block_var_name_2 = workspace.topBlocks_[1].getVars()[0];
|
||||
assertNull(variable);
|
||||
assertEquals(newName, block_var_name_1);
|
||||
assertEquals(newName, block_var_name_2);
|
||||
workspaceTest_tearDown();
|
||||
}
|
||||
|
||||
function test_deleteVariable_Trivial() {
|
||||
workspaceTest_setUp();
|
||||
// TODO (#1199): make a similar test where the variable is given a non-empty
|
||||
// type.
|
||||
workspace.createVariable('name1', '', 'id1');
|
||||
workspace.createVariable('name2', '', 'id2');
|
||||
createMockBlock('name1');
|
||||
createMockBlock('name2');
|
||||
|
||||
workspace.deleteVariable('name1', '');
|
||||
checkVariableValues(workspace, 'name2', '', 'id2');
|
||||
var variable = workspace.getVariable('name1', '');
|
||||
var block_var_name = workspace.topBlocks_[0].getVars()[0];
|
||||
assertNull(variable);
|
||||
assertEquals('name2', block_var_name);
|
||||
workspaceTest_tearDown();
|
||||
}
|
||||
|
||||
function test_deleteVariableById_Trivial() {
|
||||
workspaceTest_setUp();
|
||||
// TODO (#1199): Make a version of this test that uses different types.
|
||||
workspace.createVariable('name1', '', 'id1');
|
||||
workspace.createVariable('name2', '', 'id2');
|
||||
createMockBlock('name1');
|
||||
createMockBlock('name2');
|
||||
createTwoVariablesAndBlocks(workspace);
|
||||
|
||||
workspace.deleteVariableById('id1');
|
||||
checkVariableValues(workspace, 'name2', '', 'id2');
|
||||
var variable = workspace.getVariable('name1', '');
|
||||
var block_var_name = workspace.topBlocks_[0].getVars()[0];
|
||||
checkVariableValues(workspace, 'name2', 'type2', 'id2');
|
||||
var variable = workspace.getVariableById('id1');
|
||||
var block_var_name = workspace.topBlocks_[0].getVarModels()[0].name;
|
||||
assertNull(variable);
|
||||
assertEquals('name2', block_var_name);
|
||||
workspaceTest_tearDown();
|
||||
|
||||
@@ -33,16 +33,6 @@ goog.require('goog.testing.MockControl');
|
||||
var workspace;
|
||||
var mockControl_;
|
||||
var savedFireFunc = Blockly.Events.fire;
|
||||
Blockly.defineBlocksWithJsonArray([{
|
||||
"type": "get_var_block",
|
||||
"message0": "%1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_variable",
|
||||
"name": "VAR",
|
||||
}
|
||||
]
|
||||
}]);
|
||||
|
||||
function temporary_fireEvent(event) {
|
||||
if (!Blockly.Events.isEnabled()) {
|
||||
@@ -53,28 +43,19 @@ function temporary_fireEvent(event) {
|
||||
}
|
||||
|
||||
function undoRedoTest_setUp() {
|
||||
defineGetVarBlock();
|
||||
workspace = new Blockly.Workspace();
|
||||
mockControl_ = new goog.testing.MockControl();
|
||||
Blockly.Events.fire = temporary_fireEvent;
|
||||
}
|
||||
|
||||
function undoRedoTest_tearDown() {
|
||||
undefineGetVarBlock();
|
||||
mockControl_.$tearDown();
|
||||
workspace.dispose();
|
||||
Blockly.Events.fire = savedFireFunc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a test get_var_block.
|
||||
* @param {string} variableName The string to put into the variable field.
|
||||
* @return {!Blockly.Block} The created block.
|
||||
*/
|
||||
function createMockBlock(variableName) {
|
||||
var block = new Blockly.Block(workspace, 'get_var_block');
|
||||
block.inputList[0].fieldRow[0].setValue(variableName);
|
||||
return block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the top block with the given index contains a variable with
|
||||
* the given name.
|
||||
@@ -82,7 +63,7 @@ function createMockBlock(variableName) {
|
||||
* @param {string} name The expected name of the variable in the block.
|
||||
*/
|
||||
function undoRedoTest_checkBlockVariableName(blockIndex, name) {
|
||||
var blockVarName = workspace.topBlocks_[blockIndex].getVars()[0];
|
||||
var blockVarName = workspace.topBlocks_[blockIndex].getVarModels()[0].name;
|
||||
assertEquals(name, blockVarName);
|
||||
}
|
||||
|
||||
@@ -91,10 +72,14 @@ function createTwoVarsEmptyType() {
|
||||
workspace.createVariable('name2', '', 'id2');
|
||||
}
|
||||
|
||||
function test_undoCreateVariable_Trivial() {
|
||||
undoRedoTest_setUp();
|
||||
function createTwoVarsDifferentTypes() {
|
||||
workspace.createVariable('name1', 'type1', 'id1');
|
||||
workspace.createVariable('name2', 'type2', 'id2');
|
||||
}
|
||||
|
||||
function test_undoCreateVariable_Trivial() {
|
||||
undoRedoTest_setUp();
|
||||
createTwoVarsDifferentTypes();
|
||||
|
||||
workspace.undo();
|
||||
checkVariableValues(workspace, 'name1', 'type1', 'id1');
|
||||
@@ -107,8 +92,7 @@ function test_undoCreateVariable_Trivial() {
|
||||
|
||||
function test_redoAndUndoCreateVariable_Trivial() {
|
||||
undoRedoTest_setUp();
|
||||
workspace.createVariable('name1', 'type1', 'id1');
|
||||
workspace.createVariable('name2', 'type2', 'id2');
|
||||
createTwoVarsDifferentTypes();
|
||||
|
||||
workspace.undo();
|
||||
workspace.undo(true);
|
||||
@@ -129,8 +113,7 @@ function test_redoAndUndoCreateVariable_Trivial() {
|
||||
|
||||
function test_undoDeleteVariable_NoBlocks() {
|
||||
undoRedoTest_setUp();
|
||||
workspace.createVariable('name1', 'type1', 'id1');
|
||||
workspace.createVariable('name2', 'type2', 'id2');
|
||||
createTwoVarsDifferentTypes();
|
||||
workspace.deleteVariableById('id1');
|
||||
workspace.deleteVariableById('id2');
|
||||
|
||||
@@ -146,32 +129,30 @@ function test_undoDeleteVariable_NoBlocks() {
|
||||
|
||||
function test_undoDeleteVariable_WithBlocks() {
|
||||
undoRedoTest_setUp();
|
||||
// TODO (#1199): make a similar test where the variable is given a non-empty
|
||||
// type.
|
||||
workspace.createVariable('name1', '', 'id1');
|
||||
workspace.createVariable('name2', '', 'id2');
|
||||
createMockBlock('name1');
|
||||
createMockBlock('name2');
|
||||
|
||||
createTwoVariablesAndBlocks(workspace);
|
||||
|
||||
workspace.deleteVariableById('id1');
|
||||
workspace.deleteVariableById('id2');
|
||||
|
||||
workspace.undo();
|
||||
undoRedoTest_checkBlockVariableName(0, 'name2');
|
||||
assertNull(workspace.getVariableById('id1'));
|
||||
checkVariableValues(workspace, 'name2', '', 'id2');
|
||||
checkVariableValues(workspace, 'name2', 'type2', 'id2');
|
||||
|
||||
workspace.undo();
|
||||
undoRedoTest_checkBlockVariableName(0, 'name2');
|
||||
undoRedoTest_checkBlockVariableName(1, 'name1');
|
||||
checkVariableValues(workspace, 'name1', '', 'id1');
|
||||
checkVariableValues(workspace, 'name2', '', 'id2');
|
||||
checkVariableValues(workspace, 'name1', 'type1', 'id1');
|
||||
checkVariableValues(workspace, 'name2', 'type2', 'id2');
|
||||
undoRedoTest_tearDown();
|
||||
}
|
||||
|
||||
function test_redoAndUndoDeleteVariable_NoBlocks() {
|
||||
undoRedoTest_setUp();
|
||||
workspace.createVariable('name1', 'type1', 'id1');
|
||||
workspace.createVariable('name2', 'type2', 'id2');
|
||||
|
||||
createTwoVarsDifferentTypes();
|
||||
|
||||
workspace.deleteVariableById('id1');
|
||||
workspace.deleteVariableById('id2');
|
||||
|
||||
@@ -192,12 +173,9 @@ function test_redoAndUndoDeleteVariable_NoBlocks() {
|
||||
|
||||
function test_redoAndUndoDeleteVariable_WithBlocks() {
|
||||
undoRedoTest_setUp();
|
||||
// TODO (#1199): make a similar test where the variable is given a non-empty
|
||||
// type.
|
||||
workspace.createVariable('name1', '', 'id1');
|
||||
workspace.createVariable('name2', '', 'id2');
|
||||
createMockBlock('name1');
|
||||
createMockBlock('name2');
|
||||
|
||||
createTwoVariablesAndBlocks(workspace);
|
||||
|
||||
workspace.deleteVariableById('id1');
|
||||
workspace.deleteVariableById('id2');
|
||||
|
||||
@@ -214,7 +192,7 @@ function test_redoAndUndoDeleteVariable_WithBlocks() {
|
||||
// Expect that variable 'id2' is recreated
|
||||
undoRedoTest_checkBlockVariableName(0, 'name2');
|
||||
assertNull(workspace.getVariableById('id1'));
|
||||
checkVariableValues(workspace, 'name2', '', 'id2');
|
||||
checkVariableValues(workspace, 'name2', 'type2', 'id2');
|
||||
undoRedoTest_tearDown();
|
||||
}
|
||||
|
||||
@@ -245,12 +223,11 @@ function test_redoAndUndoDeleteVariableTwice_NoBlocks() {
|
||||
|
||||
function test_redoAndUndoDeleteVariableTwice_WithBlocks() {
|
||||
undoRedoTest_setUp();
|
||||
// TODO (#1199): make a similar test where the variable is given a non-empty
|
||||
// type.
|
||||
workspace.createVariable('name1', '', 'id1');
|
||||
createMockBlock('name1');
|
||||
workspace.deleteVariableById('id1');
|
||||
workspace.deleteVariableById('id1');
|
||||
var id = 'id1';
|
||||
workspace.createVariable('name1', 'type1', id);
|
||||
createMockBlock(id);
|
||||
workspace.deleteVariableById(id);
|
||||
workspace.deleteVariableById(id);
|
||||
|
||||
// Check the undoStack only recorded one delete event.
|
||||
var undoStack = workspace.undoStack_;
|
||||
@@ -261,45 +238,27 @@ function test_redoAndUndoDeleteVariableTwice_WithBlocks() {
|
||||
// undo delete
|
||||
workspace.undo();
|
||||
undoRedoTest_checkBlockVariableName(0, 'name1');
|
||||
checkVariableValues(workspace, 'name1', '', 'id1');
|
||||
checkVariableValues(workspace, 'name1', 'type1', id);
|
||||
|
||||
// redo delete
|
||||
workspace.undo(true);
|
||||
assertEquals(0, workspace.topBlocks_.length);
|
||||
assertNull(workspace.getVariableById('id1'));
|
||||
assertNull(workspace.getVariableById(id));
|
||||
|
||||
// redo delete, nothing should happen
|
||||
workspace.undo(true);
|
||||
assertEquals(0, workspace.topBlocks_.length);
|
||||
assertNull(workspace.getVariableById('id1'));
|
||||
undoRedoTest_tearDown();
|
||||
}
|
||||
|
||||
function test_undoRedoRenameVariable_NeitherVariableExists() {
|
||||
// Expect that a variable with the name, 'name2', and the generated UUID,
|
||||
// 'id2', to be created when rename is called. Undo removes this variable
|
||||
// and redo recreates it.
|
||||
undoRedoTest_setUp();
|
||||
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null,
|
||||
['rename_group', 'id2', 'delete_group']);
|
||||
workspace.renameVariable('name1', 'name2');
|
||||
|
||||
workspace.undo();
|
||||
assertNull(workspace.getVariableById('id2'));
|
||||
|
||||
workspace.undo(true);
|
||||
checkVariableValues(workspace, 'name2', '', 'id2');
|
||||
assertNull(workspace.getVariableById(id));
|
||||
undoRedoTest_tearDown();
|
||||
}
|
||||
|
||||
function test_undoRedoRenameVariable_OneExists_NoBlocks() {
|
||||
undoRedoTest_setUp();
|
||||
workspace.createVariable('name1', '', 'id1');
|
||||
workspace.renameVariable('name1', 'name2');
|
||||
workspace.renameVariableById('id1', 'name2');
|
||||
|
||||
workspace.undo();
|
||||
checkVariableValues(workspace, 'name1', '', 'id1');
|
||||
assertNull(workspace.getVariable('name2'));
|
||||
|
||||
workspace.undo(true);
|
||||
checkVariableValues(workspace, 'name2', '', 'id1');
|
||||
@@ -309,13 +268,12 @@ function test_undoRedoRenameVariable_OneExists_NoBlocks() {
|
||||
function test_undoRedoRenameVariable_OneExists_WithBlocks() {
|
||||
undoRedoTest_setUp();
|
||||
workspace.createVariable('name1', '', 'id1');
|
||||
createMockBlock('name1');
|
||||
workspace.renameVariable('name1', 'name2');
|
||||
createMockBlock('id1');
|
||||
workspace.renameVariableById('id1', 'name2');
|
||||
|
||||
workspace.undo();
|
||||
undoRedoTest_checkBlockVariableName(0, 'name1');
|
||||
checkVariableValues(workspace, 'name1', '', 'id1');
|
||||
assertNull(workspace.getVariable('name2'));
|
||||
|
||||
workspace.undo(true);
|
||||
checkVariableValues(workspace, 'name2', '', 'id1');
|
||||
@@ -326,7 +284,7 @@ function test_undoRedoRenameVariable_OneExists_WithBlocks() {
|
||||
function test_undoRedoRenameVariable_BothExist_NoBlocks() {
|
||||
undoRedoTest_setUp();
|
||||
createTwoVarsEmptyType();
|
||||
workspace.renameVariable('name1', 'name2');
|
||||
workspace.renameVariableById('id1', 'name2');
|
||||
|
||||
workspace.undo();
|
||||
checkVariableValues(workspace, 'name1', '', 'id1');
|
||||
@@ -334,16 +292,16 @@ function test_undoRedoRenameVariable_BothExist_NoBlocks() {
|
||||
|
||||
workspace.undo(true);
|
||||
checkVariableValues(workspace, 'name2', '', 'id2');
|
||||
assertNull(workspace.getVariable('name1'));
|
||||
assertNull(workspace.getVariableById('id1'));
|
||||
undoRedoTest_tearDown();
|
||||
}
|
||||
|
||||
function test_undoRedoRenameVariable_BothExist_WithBlocks() {
|
||||
undoRedoTest_setUp();
|
||||
createTwoVarsEmptyType();
|
||||
createMockBlock('name1');
|
||||
createMockBlock('name2');
|
||||
workspace.renameVariable('name1', 'name2');
|
||||
createMockBlock('id1');
|
||||
createMockBlock('id2');
|
||||
workspace.renameVariableById('id1', 'name2');
|
||||
|
||||
workspace.undo();
|
||||
undoRedoTest_checkBlockVariableName(0, 'name1');
|
||||
@@ -360,7 +318,7 @@ function test_undoRedoRenameVariable_BothExist_WithBlocks() {
|
||||
function test_undoRedoRenameVariable_BothExistCaseChange_NoBlocks() {
|
||||
undoRedoTest_setUp();
|
||||
createTwoVarsEmptyType();
|
||||
workspace.renameVariable('name1', 'Name2');
|
||||
workspace.renameVariableById('id1', 'Name2');
|
||||
|
||||
workspace.undo();
|
||||
checkVariableValues(workspace, 'name1', '', 'id1');
|
||||
@@ -375,9 +333,9 @@ function test_undoRedoRenameVariable_BothExistCaseChange_NoBlocks() {
|
||||
function test_undoRedoRenameVariable_BothExistCaseChange_WithBlocks() {
|
||||
undoRedoTest_setUp();
|
||||
createTwoVarsEmptyType();
|
||||
createMockBlock('name1');
|
||||
createMockBlock('name2');
|
||||
workspace.renameVariable('name1', 'Name2');
|
||||
createMockBlock('id1');
|
||||
createMockBlock('id2');
|
||||
workspace.renameVariableById('id1', 'Name2');
|
||||
|
||||
workspace.undo();
|
||||
undoRedoTest_checkBlockVariableName(0, 'name1');
|
||||
@@ -387,7 +345,7 @@ function test_undoRedoRenameVariable_BothExistCaseChange_WithBlocks() {
|
||||
|
||||
workspace.undo(true);
|
||||
checkVariableValues(workspace, 'Name2', '', 'id2');
|
||||
assertNull(workspace.getVariable('name1'));
|
||||
assertNull(workspace.getVariableById('id1'));
|
||||
undoRedoTest_checkBlockVariableName(0, 'Name2');
|
||||
undoRedoTest_checkBlockVariableName(1, 'Name2');
|
||||
undoRedoTest_tearDown();
|
||||
@@ -396,7 +354,7 @@ function test_undoRedoRenameVariable_BothExistCaseChange_WithBlocks() {
|
||||
function test_undoRedoRenameVariable_OnlyCaseChange_NoBlocks() {
|
||||
undoRedoTest_setUp();
|
||||
workspace.createVariable('name1', '', 'id1');
|
||||
workspace.renameVariable('name1', 'Name1');
|
||||
workspace.renameVariableById('id1', 'Name1');
|
||||
|
||||
workspace.undo();
|
||||
checkVariableValues(workspace, 'name1', '', 'id1');
|
||||
@@ -409,8 +367,8 @@ function test_undoRedoRenameVariable_OnlyCaseChange_NoBlocks() {
|
||||
function test_undoRedoRenameVariable_OnlyCaseChange_WithBlocks() {
|
||||
undoRedoTest_setUp();
|
||||
workspace.createVariable('name1', '', 'id1');
|
||||
createMockBlock('name1');
|
||||
workspace.renameVariable('name1', 'Name1');
|
||||
createMockBlock('id1');
|
||||
workspace.renameVariableById('id1', 'Name1');
|
||||
|
||||
workspace.undo();
|
||||
undoRedoTest_checkBlockVariableName(0, 'name1');
|
||||
|
||||
@@ -286,10 +286,10 @@ function test_appendDomToWorkspace() {
|
||||
function test_blockToDom_fieldToDom_trivial() {
|
||||
xmlTest_setUpWithMockBlocks();
|
||||
// TODO (#1199): make a similar test where the variable is given a non-empty
|
||||
// type.
|
||||
// type.f
|
||||
workspace.createVariable('name1', '', 'id1');
|
||||
var block = new Blockly.Block(workspace, 'field_variable_test_block');
|
||||
block.inputList[0].fieldRow[0].setValue('name1');
|
||||
block.inputList[0].fieldRow[0].setValue('id1');
|
||||
var resultFieldDom = Blockly.Xml.blockToDom(block).childNodes[0];
|
||||
xmlTest_checkVariableFieldDomValues(resultFieldDom, 'VAR', '', 'id1',
|
||||
'name1');
|
||||
@@ -301,7 +301,7 @@ function test_blockToDom_fieldToDom_defaultCase() {
|
||||
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1', '1']);
|
||||
workspace.createVariable('name1');
|
||||
var block = new Blockly.Block(workspace, 'field_variable_test_block');
|
||||
block.inputList[0].fieldRow[0].setValue('name1');
|
||||
block.inputList[0].fieldRow[0].setValue('1');
|
||||
var resultFieldDom = Blockly.Xml.blockToDom(block).childNodes[0];
|
||||
// Expect type is '' and id is '1' since we don't specify type and id.
|
||||
xmlTest_checkVariableFieldDomValues(resultFieldDom, 'VAR', '', '1', 'name1');
|
||||
@@ -345,14 +345,14 @@ function test_variablesToDom_oneVariable() {
|
||||
function test_variablesToDom_twoVariables_oneBlock() {
|
||||
xmlTest_setUpWithMockBlocks();
|
||||
|
||||
workspace.createVariable('name1', 'type1', 'id1');
|
||||
workspace.createVariable('name1', '', 'id1');
|
||||
workspace.createVariable('name2', 'type2', 'id2');
|
||||
var block = new Blockly.Block(workspace, 'field_variable_test_block');
|
||||
block.inputList[0].fieldRow[0].setValue('name1');
|
||||
block.inputList[0].fieldRow[0].setValue('id1');
|
||||
|
||||
var resultDom = Blockly.Xml.variablesToDom(workspace.getAllVariables());
|
||||
assertEquals(2, resultDom.children.length);
|
||||
xmlTest_checkVariableDomValues(resultDom.children[0], 'type1', 'id1',
|
||||
xmlTest_checkVariableDomValues(resultDom.children[0], '', 'id1',
|
||||
'name1');
|
||||
xmlTest_checkVariableDomValues(resultDom.children[1], 'type2', 'id2',
|
||||
'name2');
|
||||
@@ -380,14 +380,12 @@ function test_variableFieldXml_caseSensitive() {
|
||||
}
|
||||
};
|
||||
|
||||
var generatedXml = Blockly.Variables.generateVariableFieldXml_(mockVariableModel);
|
||||
// The field contains this XML tag as a result of how we're generating this
|
||||
// XML. This is not desirable, but the goal of this test is to make sure
|
||||
// we're preserving case-sensitivity.
|
||||
var xmlns = 'xmlns="http://www.w3.org/1999/xhtml"';
|
||||
var generatedXml =
|
||||
Blockly.Variables.generateVariableFieldXml_(mockVariableModel);
|
||||
var goldenXml =
|
||||
'<field ' + xmlns + ' name="VAR"' +
|
||||
'<field name="VAR"' +
|
||||
' id="' + id + '"' +
|
||||
' variabletype="' + type + '"' +
|
||||
' id="' + id + '">' + name + '</field>';
|
||||
'>' + name + '</field>';
|
||||
assertEquals(goldenXml, generatedXml);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user