mirror of
https://github.com/google/blockly.git
synced 2026-01-08 17:40:09 +01:00
Can now create a variable with the button in the flyout; drag a block with a variable out of the flyout; handle default variable names; and import and export variables
This commit is contained in:
@@ -47,13 +47,45 @@ 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 || '');
|
||||
// Don't call the FieldDropdown constructor. It'll try too hard.
|
||||
this.menuGenerator_ = Blockly.FieldVariable.dropdownCreate;
|
||||
this.size_ = new goog.math.Size(0, Blockly.BlockSvg.MIN_BLOCK_Y);
|
||||
this.setValidator(opt_validator);
|
||||
//this.setValue(varname || '');
|
||||
// TODO: Add opt_default_type to match default value. If not set, ''.
|
||||
this.defaultVariableName = (varname || '');
|
||||
this.defaultType_ = '';
|
||||
this.variableTypes = opt_variableTypes;
|
||||
};
|
||||
goog.inherits(Blockly.FieldVariable, Blockly.FieldDropdown);
|
||||
|
||||
Blockly.FieldVariable.getOrCreateVariable = function(workspace, text, type,
|
||||
id) {
|
||||
var potentialVariableMap = workspace.isFlyout ?
|
||||
workspace.targetWorkspace.potentialVariableMap_ : null;
|
||||
if (id) {
|
||||
var variable = workspace.getVariableById(id);
|
||||
if (!variable && potentialVariableMap) {
|
||||
variable = potentialVariableMap.getVariableById(id);
|
||||
}
|
||||
} else {
|
||||
var variable = workspace.getVariable(text, type);
|
||||
if (!variable && potentialVariableMap) {
|
||||
variable = potentialVariableMap.getVariable(text, type);
|
||||
}
|
||||
}
|
||||
// Didn't find the variable.
|
||||
if (!variable) {
|
||||
if (potentialVariableMap) {
|
||||
variable = potentialVariableMap.createVariable(text, type, id);
|
||||
} else {
|
||||
variable = workspace.createVariable(text, type, id);
|
||||
}
|
||||
}
|
||||
|
||||
return variable;
|
||||
};
|
||||
|
||||
/**
|
||||
* Install this dropdown on a block.
|
||||
*/
|
||||
@@ -69,20 +101,39 @@ Blockly.FieldVariable.prototype.init = function() {
|
||||
};
|
||||
|
||||
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());
|
||||
// this.workspace_ = this.sourceBlock_.isInFlyout ?
|
||||
// this.sourceBlock_.workspace.targetWorkspace :
|
||||
// this.sourceBlock_.workspace;
|
||||
// // TODO: Describe how the potential variable map is different from the variable
|
||||
// // map; use getters.
|
||||
// this.variableMap_ = this.sourceBlock_.isInFlyout ?
|
||||
// this.workspace_.potentialVariableMap_ : this.workspace_.variableMap_;
|
||||
// var name = this.defaultValue;
|
||||
// if (!name) {
|
||||
// // Variables without names get uniquely named for this workspace.
|
||||
// name = Blockly.Variables.generateUniqueName(this.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.
|
||||
|
||||
// var variable = this.variableMap_.getVariable(name, this.defaultType_);
|
||||
// if (!variable) {
|
||||
// variable = this.variableMap_.createVariable(name, this.defaultType_);
|
||||
// }
|
||||
if (this.variable_) {
|
||||
return; // Initialization already happened.
|
||||
}
|
||||
this.workspace_ = this.sourceBlock_.workspace;
|
||||
var variable = Blockly.FieldVariable.getOrCreateVariable(
|
||||
this.workspace_, this.defaultVariableName, this.defaultType_, null);
|
||||
this.setValue(variable.getId());
|
||||
};
|
||||
|
||||
Blockly.FieldVariable.dispose = function() {
|
||||
Blockly.FieldVariable.superClass_.dispose.call(this);
|
||||
this.workspace_ = null;
|
||||
this.variableMap_ = null;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -101,14 +152,20 @@ Blockly.FieldVariable.prototype.setSourceBlock = function(block) {
|
||||
* @return {string} Current text.
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.getValue = function() {
|
||||
return this.getText();
|
||||
//return this.getText();
|
||||
return this.variable_ ? this.variable_.getId() : '';
|
||||
};
|
||||
|
||||
Blockly.FieldVariable.prototype.getText = function() {
|
||||
//return this.getText();
|
||||
return this.variable_ ? this.variable_.name : '';
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the variable name.
|
||||
* Set the variable name. (DEPRECATED)
|
||||
* @param {string} value New text.
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.setValue = function(value) {
|
||||
Blockly.FieldVariable.prototype.oldSetValue = function(value) {
|
||||
var newValue = value;
|
||||
var newText = value;
|
||||
|
||||
@@ -131,6 +188,47 @@ Blockly.FieldVariable.prototype.setValue = function(value) {
|
||||
this.setText(newText);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the variable ID.
|
||||
* @param {string} id New variable ID, which must reference an existing
|
||||
* variable.
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.setValue = function(id) {
|
||||
var workspace = this.sourceBlock_.workspace;
|
||||
//var variable = this.variableMap_.getVariableById(id);
|
||||
var potentialVariableMap = workspace.isFlyout ?
|
||||
workspace.targetWorkspace.potentialVariableMap_ : null;
|
||||
var variable = workspace.getVariableById(id);
|
||||
if (!variable && potentialVariableMap) {
|
||||
variable = potentialVariableMap.getVariableById(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);
|
||||
}
|
||||
this.variable_ = variable;
|
||||
this.setText(variable.name);
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a list of variable types to include in the dropdown.
|
||||
* @return {!Array.<string>} Array of variable types.
|
||||
@@ -138,6 +236,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 || variableTypes === undefined) {
|
||||
// If variableTypes is null, return all variable types.
|
||||
@@ -234,7 +334,7 @@ Blockly.FieldVariable.prototype.onItemSelected = function(menu, menuItem) {
|
||||
return;
|
||||
} else if (id == Blockly.DELETE_VARIABLE_ID) {
|
||||
// Delete variable.
|
||||
workspace.deleteVariable(this.getText());
|
||||
workspace.deleteVariableById(this.variable_.getId());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -330,12 +330,20 @@ 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 typeString = variableModel.type;
|
||||
if (typeString == '') {
|
||||
typeString = '\'\'';
|
||||
}
|
||||
var text = '<field name="VAR" id="' + variableModel.getId() +
|
||||
'" variabletype="' + typeString +
|
||||
'">' + variableModel.name + '</field>';
|
||||
return text;
|
||||
// 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 xmlString = Blockly.Xml.domToText(element);
|
||||
// return xmlString;
|
||||
};
|
||||
|
||||
@@ -84,6 +84,8 @@ Blockly.Workspace = function(opt_options) {
|
||||
* @private
|
||||
*/
|
||||
this.variableMap_ = new Blockly.VariableMap(this);
|
||||
|
||||
this.potentialVariableMap_ = new Blockly.VariableMap(this);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
85
core/xml.js
85
core/xml.js
@@ -86,6 +86,28 @@ Blockly.Xml.blockToDomWithXY = function(block, opt_noId) {
|
||||
return element;
|
||||
};
|
||||
|
||||
Blockly.Xml.fieldToDomVariable_ = function(field, workspace) {
|
||||
var potentialVariableMap = workspace.isFlyout ?
|
||||
workspace.targetWorkspace.potentialVariableMap_ : null;
|
||||
// Ugh that's not true at all.
|
||||
var id = field.getValue();
|
||||
var variable = workspace.getVariableById(id);
|
||||
if (!variable && 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.log('no variable in fieldtodom');
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a field as XML.
|
||||
* @param {!Blockly.Field} field The field to encode.
|
||||
@@ -96,16 +118,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;
|
||||
};
|
||||
@@ -698,6 +717,31 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) {
|
||||
return block;
|
||||
};
|
||||
|
||||
Blockly.Xml.domToFieldVariable_ = function(workspace, xml, text, field) {
|
||||
// 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') || '';
|
||||
if (type == '\'\'') {
|
||||
type = '';
|
||||
}
|
||||
// TODO: Consider using a different name (var_id?) because this is the
|
||||
// node's ID.
|
||||
var id = xml.id;
|
||||
var variable = Blockly.FieldVariable.getOrCreateVariable(workspace, text,
|
||||
type, id);
|
||||
|
||||
// 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 +760,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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user