Merge pull request #5178 from gonfunko/field_variable

Migrate core/field_variable.js to goog.module syntax
This commit is contained in:
Aaron Dodson
2021-07-22 12:49:56 -07:00
committed by GitHub
2 changed files with 118 additions and 113 deletions

View File

@@ -10,24 +10,24 @@
*/
'use strict';
goog.provide('Blockly.FieldVariable');
goog.module('Blockly.FieldVariable');
goog.module.declareLegacyNamespace();
const Block = goog.requireType('Blockly.Block');
const FieldDropdown = goog.require('Blockly.FieldDropdown');
const Menu = goog.requireType('Blockly.Menu');
const MenuItem = goog.requireType('Blockly.MenuItem');
const Msg = goog.require('Blockly.Msg');
const Size = goog.require('Blockly.utils.Size');
const VariableModel = goog.require('Blockly.VariableModel');
const Variables = goog.require('Blockly.Variables');
const Xml = goog.require('Blockly.Xml');
const fieldRegistry = goog.require('Blockly.fieldRegistry');
const internalConstants = goog.require('Blockly.internalConstants');
const {inherits} = goog.require('Blockly.utils.object');
const {replaceMessageReferences} = goog.require('Blockly.utils');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.BlockChange');
goog.require('Blockly.FieldDropdown');
goog.require('Blockly.fieldRegistry');
goog.require('Blockly.internalConstants');
goog.require('Blockly.Msg');
goog.require('Blockly.utils');
goog.require('Blockly.utils.object');
goog.require('Blockly.utils.Size');
goog.require('Blockly.VariableModel');
goog.require('Blockly.Variables');
goog.require('Blockly.Xml');
goog.requireType('Blockly.Block');
goog.requireType('Blockly.Menu');
goog.requireType('Blockly.MenuItem');
/**
@@ -42,13 +42,14 @@ goog.requireType('Blockly.MenuItem');
* @param {string=} opt_defaultType The type of variable to create if this
* field's value is not explicitly set. Defaults to ''.
* @param {Object=} opt_config A map of options used to configure the field.
* See the [field creation documentation]{@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/variable#creation}
* See the [field creation documentation]{@link
* https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/variable#creation}
* for a list of properties this parameter supports.
* @extends {Blockly.FieldDropdown}
* @extends {FieldDropdown}
* @constructor
*/
Blockly.FieldVariable = function(varName, opt_validator, opt_variableTypes,
opt_defaultType, opt_config) {
const FieldVariable = function(
varName, opt_validator, opt_variableTypes, opt_defaultType, opt_config) {
// The FieldDropdown constructor expects the field's initial value to be
// the first entry in the menu generator, which it may or may not be.
// Just do the relevant parts of the constructor.
@@ -57,10 +58,10 @@ Blockly.FieldVariable = function(varName, opt_validator, opt_variableTypes,
* An array of options for a dropdown list,
* or a function which generates these options.
* @type {(!Array<!Array>|
* !function(this:Blockly.FieldDropdown): !Array<!Array>)}
* !function(this:FieldDropdown): !Array<!Array>)}
* @protected
*/
this.menuGenerator_ = Blockly.FieldVariable.dropdownCreate;
this.menuGenerator_ = FieldVariable.dropdownCreate;
/**
* The initial variable name passed to this field's constructor, or an
@@ -72,11 +73,11 @@ Blockly.FieldVariable = function(varName, opt_validator, opt_variableTypes,
/**
* The size of the area rendered by the field.
* @type {Blockly.utils.Size}
* @type {Size}
* @protected
* @override
*/
this.size_ = new Blockly.utils.Size(0, 0);
this.size_ = new Size(0, 0);
opt_config && this.configure_(opt_config);
opt_validator && this.setValidator(opt_validator);
@@ -85,19 +86,19 @@ Blockly.FieldVariable = function(varName, opt_validator, opt_variableTypes,
this.setTypes_(opt_variableTypes, opt_defaultType);
}
};
Blockly.utils.object.inherits(Blockly.FieldVariable, Blockly.FieldDropdown);
inherits(FieldVariable, FieldDropdown);
/**
* Construct a FieldVariable from a JSON arg object,
* dereferencing any string table references.
* @param {!Object} options A JSON object with options (variable,
* variableTypes, and defaultType).
* @return {!Blockly.FieldVariable} The new field instance.
* @return {!FieldVariable} The new field instance.
* @package
* @nocollapse
*/
Blockly.FieldVariable.fromJson = function(options) {
var varName = Blockly.utils.replaceMessageReferences(options['variable']);
FieldVariable.fromJson = function(options) {
const varName = replaceMessageReferences(options['variable']);
// `this` might be a subclass of FieldVariable if that class doesn't override
// the static fromJson method.
return new this(varName, undefined, undefined, undefined, options);
@@ -108,15 +109,15 @@ Blockly.FieldVariable.fromJson = function(options) {
* are not. Editable fields should also be serializable.
* @type {boolean}
*/
Blockly.FieldVariable.prototype.SERIALIZABLE = true;
FieldVariable.prototype.SERIALIZABLE = true;
/**
* Configure the field based on the given map of options.
* @param {!Object} config A map of options to configure the field based on.
* @protected
*/
Blockly.FieldVariable.prototype.configure_ = function(config) {
Blockly.FieldVariable.superClass_.configure_.call(this, config);
FieldVariable.prototype.configure_ = function(config) {
FieldVariable.superClass_.configure_.call(this, config);
this.setTypes_(config['variableTypes'], config['defaultType']);
};
@@ -126,13 +127,13 @@ Blockly.FieldVariable.prototype.configure_ = function(config) {
* variable rather than let the value be invalid.
* @package
*/
Blockly.FieldVariable.prototype.initModel = function() {
FieldVariable.prototype.initModel = function() {
if (this.variable_) {
return; // Initialization already happened.
}
var variable = Blockly.Variables.getOrCreateVariablePackage(
this.sourceBlock_.workspace, null,
this.defaultVariableName, this.defaultType_);
const variable = Variables.getOrCreateVariablePackage(
this.sourceBlock_.workspace, null, this.defaultVariableName,
this.defaultType_);
// Don't call setValue because we don't want to cause a rerender.
this.doValueUpdate_(variable.getId());
@@ -141,10 +142,10 @@ Blockly.FieldVariable.prototype.initModel = function() {
/**
* @override
*/
Blockly.FieldVariable.prototype.shouldAddBorderRect_ = function() {
return Blockly.FieldVariable.superClass_.shouldAddBorderRect_.call(this) &&
(!this.getConstants().FIELD_DROPDOWN_NO_BORDER_RECT_SHADOW ||
this.sourceBlock_.type != 'variables_get');
FieldVariable.prototype.shouldAddBorderRect_ = function() {
return FieldVariable.superClass_.shouldAddBorderRect_.call(this) &&
(!this.getConstants().FIELD_DROPDOWN_NO_BORDER_RECT_SHADOW ||
this.sourceBlock_.type != 'variables_get');
};
/**
@@ -152,23 +153,24 @@ Blockly.FieldVariable.prototype.shouldAddBorderRect_ = function() {
* @param {!Element} fieldElement The element containing information about the
* variable field's state.
*/
Blockly.FieldVariable.prototype.fromXml = function(fieldElement) {
var id = fieldElement.getAttribute('id');
var variableName = fieldElement.textContent;
FieldVariable.prototype.fromXml = function(fieldElement) {
const id = fieldElement.getAttribute('id');
const variableName = fieldElement.textContent;
// 'variabletype' should be lowercase, but until July 2019 it was sometimes
// recorded as 'variableType'. Thus we need to check for both.
var variableType = fieldElement.getAttribute('variabletype') ||
const variableType = fieldElement.getAttribute('variabletype') ||
fieldElement.getAttribute('variableType') || '';
var variable = Blockly.Variables.getOrCreateVariablePackage(
const variable = Variables.getOrCreateVariablePackage(
this.sourceBlock_.workspace, id, variableName, variableType);
// This should never happen :)
if (variableType != null && variableType !== 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(fieldElement) + '.');
throw Error(
'Serialized variable type with id \'' + variable.getId() +
'\' had type ' + variable.type + ', and ' +
'does not match variable field that references it: ' +
Xml.domToText(fieldElement) + '.');
}
this.setValue(variable.getId());
@@ -180,7 +182,7 @@ Blockly.FieldVariable.prototype.fromXml = function(fieldElement) {
* field's state.
* @return {!Element} The element containing info about the field's state.
*/
Blockly.FieldVariable.prototype.toXml = function(fieldElement) {
FieldVariable.prototype.toXml = function(fieldElement) {
// Make sure the variable is initialized.
this.initModel();
@@ -194,20 +196,20 @@ Blockly.FieldVariable.prototype.toXml = function(fieldElement) {
/**
* Attach this field to a block.
* @param {!Blockly.Block} block The block containing this field.
* @param {!Block} block The block containing this field.
*/
Blockly.FieldVariable.prototype.setSourceBlock = function(block) {
FieldVariable.prototype.setSourceBlock = function(block) {
if (block.isShadow()) {
throw Error('Variable fields are not allowed to exist on shadow blocks.');
}
Blockly.FieldVariable.superClass_.setSourceBlock.call(this, block);
FieldVariable.superClass_.setSourceBlock.call(this, block);
};
/**
* Get the variable's ID.
* @return {string} Current variable's ID.
*/
Blockly.FieldVariable.prototype.getValue = function() {
FieldVariable.prototype.getValue = function() {
return this.variable_ ? this.variable_.getId() : null;
};
@@ -216,7 +218,7 @@ Blockly.FieldVariable.prototype.getValue = function() {
* @return {string} The selected variable's name, or the empty string if no
* variable is selected.
*/
Blockly.FieldVariable.prototype.getText = function() {
FieldVariable.prototype.getText = function() {
return this.variable_ ? this.variable_.name : '';
};
@@ -224,11 +226,11 @@ Blockly.FieldVariable.prototype.getText = function() {
* Get the variable model for the selected variable.
* Not guaranteed to be in the variable map on the workspace (e.g. if accessed
* after the variable has been deleted).
* @return {?Blockly.VariableModel} The selected variable, or null if none was
* @return {?VariableModel} The selected variable, or null if none was
* selected.
* @package
*/
Blockly.FieldVariable.prototype.getVariable = function() {
FieldVariable.prototype.getVariable = function() {
return this.variable_;
};
@@ -239,7 +241,7 @@ Blockly.FieldVariable.prototype.getVariable = function() {
* a block and workspace at that point.
* @return {?Function} Validation function, or null.
*/
Blockly.FieldVariable.prototype.getValidator = function() {
FieldVariable.prototype.getValidator = function() {
// Validators shouldn't operate on the initial setValue call.
// Normally this is achieved by calling setValidator after setValue, but
// this is not a possibility with variable fields.
@@ -255,20 +257,20 @@ Blockly.FieldVariable.prototype.getValidator = function() {
* @return {?string} The validated ID, or null if invalid.
* @protected
*/
Blockly.FieldVariable.prototype.doClassValidation_ = function(opt_newValue) {
FieldVariable.prototype.doClassValidation_ = function(opt_newValue) {
if (opt_newValue === null) {
return null;
}
var newId = /** @type {string} */ (opt_newValue);
var variable = Blockly.Variables.getVariable(
this.sourceBlock_.workspace, newId);
const newId = /** @type {string} */ (opt_newValue);
const variable = Variables.getVariable(this.sourceBlock_.workspace, newId);
if (!variable) {
console.warn('Variable id doesn\'t point to a real variable! ' +
console.warn(
'Variable id doesn\'t point to a real variable! ' +
'ID was ' + newId);
return null;
}
// Type Checks.
var type = variable.type;
const type = variable.type;
if (!this.typeIsAllowed_(type)) {
console.warn('Variable type doesn\'t match this field! Type was ' + type);
return null;
@@ -284,10 +286,10 @@ Blockly.FieldVariable.prototype.doClassValidation_ = function(opt_newValue) {
* @param {*} newId The value to be saved.
* @protected
*/
Blockly.FieldVariable.prototype.doValueUpdate_ = function(newId) {
this.variable_ = Blockly.Variables.getVariable(
FieldVariable.prototype.doValueUpdate_ = function(newId) {
this.variable_ = Variables.getVariable(
this.sourceBlock_.workspace, /** @type {string} */ (newId));
Blockly.FieldVariable.superClass_.doValueUpdate_.call(this, newId);
FieldVariable.superClass_.doValueUpdate_.call(this, newId);
};
/**
@@ -296,12 +298,12 @@ Blockly.FieldVariable.prototype.doValueUpdate_ = function(newId) {
* @return {boolean} True if the type is in the list of allowed types.
* @private
*/
Blockly.FieldVariable.prototype.typeIsAllowed_ = function(type) {
var typeList = this.getVariableTypes_();
FieldVariable.prototype.typeIsAllowed_ = function(type) {
const typeList = this.getVariableTypes_();
if (!typeList) {
return true; // If it's null, all types are valid.
}
for (var i = 0; i < typeList.length; i++) {
for (let i = 0; i < typeList.length; i++) {
if (type == typeList[i]) {
return true;
}
@@ -315,9 +317,9 @@ Blockly.FieldVariable.prototype.typeIsAllowed_ = function(type) {
* @throws {Error} if variableTypes is an empty array.
* @private
*/
Blockly.FieldVariable.prototype.getVariableTypes_ = function() {
FieldVariable.prototype.getVariableTypes_ = function() {
// TODO (#1513): Try to avoid calling this every time the field is edited.
var variableTypes = this.variableTypes;
let variableTypes = this.variableTypes;
if (variableTypes === null) {
// If variableTypes is null, return all variable types.
if (this.sourceBlock_ && this.sourceBlock_.workspace) {
@@ -327,9 +329,9 @@ Blockly.FieldVariable.prototype.getVariableTypes_ = function() {
variableTypes = variableTypes || [''];
if (variableTypes.length == 0) {
// Throw an error if variableTypes is an empty list.
var name = this.getText();
throw Error('\'variableTypes\' of field variable ' +
name + ' was an empty list');
const name = this.getText();
throw Error(
'\'variableTypes\' of field variable ' + name + ' was an empty list');
}
return variableTypes;
};
@@ -344,29 +346,32 @@ Blockly.FieldVariable.prototype.getVariableTypes_ = function() {
* field's value is not explicitly set. Defaults to ''.
* @private
*/
Blockly.FieldVariable.prototype.setTypes_ = function(opt_variableTypes,
opt_defaultType) {
FieldVariable.prototype.setTypes_ = function(
opt_variableTypes, opt_defaultType) {
// If you expected that the default type would be the same as the only entry
// in the variable types array, tell the Blockly team by commenting on #1499.
var defaultType = opt_defaultType || '';
const defaultType = opt_defaultType || '';
let variableTypes;
// Set the allowable variable types. Null means all types on the workspace.
if (opt_variableTypes == null || opt_variableTypes == undefined) {
var variableTypes = null;
variableTypes = null;
} else if (Array.isArray(opt_variableTypes)) {
var variableTypes = opt_variableTypes;
variableTypes = opt_variableTypes;
// Make sure the default type is valid.
var isInArray = false;
for (var i = 0; i < variableTypes.length; i++) {
let isInArray = false;
for (let i = 0; i < variableTypes.length; i++) {
if (variableTypes[i] == defaultType) {
isInArray = true;
}
}
if (!isInArray) {
throw Error('Invalid default type \'' + defaultType + '\' in ' +
throw Error(
'Invalid default type \'' + defaultType + '\' in ' +
'the definition of a FieldVariable');
}
} else {
throw Error('\'variableTypes\' was not an array in the definition of ' +
throw Error(
'\'variableTypes\' was not an array in the definition of ' +
'a FieldVariable');
}
// Only update the field once all checks pass.
@@ -380,7 +385,7 @@ Blockly.FieldVariable.prototype.setTypes_ = function(opt_variableTypes,
* be called by the block.
* @package
*/
Blockly.FieldVariable.prototype.refreshVariableName = function() {
FieldVariable.prototype.refreshVariableName = function() {
this.forceRerender();
};
@@ -388,40 +393,39 @@ Blockly.FieldVariable.prototype.refreshVariableName = function() {
* Return a sorted list of variable names for variable dropdown menus.
* Include a special option at the end for creating a new variable name.
* @return {!Array<!Array>} Array of variable names/id tuples.
* @this {Blockly.FieldVariable}
* @this {FieldVariable}
*/
Blockly.FieldVariable.dropdownCreate = function() {
FieldVariable.dropdownCreate = function() {
if (!this.variable_) {
throw Error('Tried to call dropdownCreate on a variable field with no' +
throw Error(
'Tried to call dropdownCreate on a variable field with no' +
' variable selected.');
}
var name = this.getText();
var variableModelList = [];
const name = this.getText();
let variableModelList = [];
if (this.sourceBlock_ && this.sourceBlock_.workspace) {
var variableTypes = this.getVariableTypes_();
const variableTypes = this.getVariableTypes_();
// Get a copy of the list, so that adding rename and new variable options
// doesn't modify the workspace's list.
for (var i = 0; i < variableTypes.length; i++) {
var variableType = variableTypes[i];
var variables =
this.sourceBlock_.workspace.getVariablesOfType(variableType);
for (let i = 0; i < variableTypes.length; i++) {
const variableType = variableTypes[i];
const variables =
this.sourceBlock_.workspace.getVariablesOfType(variableType);
variableModelList = variableModelList.concat(variables);
}
}
variableModelList.sort(Blockly.VariableModel.compareByName);
variableModelList.sort(VariableModel.compareByName);
var options = [];
for (var i = 0; i < variableModelList.length; i++) {
const options = [];
for (let i = 0; i < variableModelList.length; i++) {
// Set the UUID as the internal representation of the variable.
options[i] = [variableModelList[i].name, variableModelList[i].getId()];
}
options.push([
Blockly.Msg['RENAME_VARIABLE'], Blockly.internalConstants.RENAME_VARIABLE_ID
]);
if (Blockly.Msg['DELETE_VARIABLE']) {
options.push([Msg['RENAME_VARIABLE'], internalConstants.RENAME_VARIABLE_ID]);
if (Msg['DELETE_VARIABLE']) {
options.push([
Blockly.Msg['DELETE_VARIABLE'].replace('%1', name),
Blockly.internalConstants.DELETE_VARIABLE_ID
Msg['DELETE_VARIABLE'].replace('%1', name),
internalConstants.DELETE_VARIABLE_ID
]);
}
@@ -432,20 +436,19 @@ Blockly.FieldVariable.dropdownCreate = function() {
* Handle the selection of an item in the variable dropdown menu.
* Special case the 'Rename variable...' and 'Delete variable...' options.
* In the rename case, prompt the user for a new name.
* @param {!Blockly.Menu} menu The Menu component clicked.
* @param {!Blockly.MenuItem} menuItem The MenuItem selected within menu.
* @param {!Menu} menu The Menu component clicked.
* @param {!MenuItem} menuItem The MenuItem selected within menu.
* @protected
*/
Blockly.FieldVariable.prototype.onItemSelected_ = function(menu, menuItem) {
var id = menuItem.getValue();
FieldVariable.prototype.onItemSelected_ = function(menu, menuItem) {
const id = menuItem.getValue();
// Handle special cases.
if (this.sourceBlock_ && this.sourceBlock_.workspace) {
if (id == Blockly.internalConstants.RENAME_VARIABLE_ID) {
if (id == internalConstants.RENAME_VARIABLE_ID) {
// Rename variable.
Blockly.Variables.renameVariable(
this.sourceBlock_.workspace, this.variable_);
Variables.renameVariable(this.sourceBlock_.workspace, this.variable_);
return;
} else if (id == Blockly.internalConstants.DELETE_VARIABLE_ID) {
} else if (id == internalConstants.DELETE_VARIABLE_ID) {
// Delete variable.
this.sourceBlock_.workspace.deleteVariableById(this.variable_.getId());
return;
@@ -461,8 +464,10 @@ Blockly.FieldVariable.prototype.onItemSelected_ = function(menu, menuItem) {
* @package
* @override
*/
Blockly.FieldVariable.prototype.referencesVariables = function() {
FieldVariable.prototype.referencesVariables = function() {
return true;
};
Blockly.fieldRegistry.register('field_variable', Blockly.FieldVariable);
fieldRegistry.register('field_variable', FieldVariable);
exports = FieldVariable;

View File

@@ -60,7 +60,7 @@ goog.addDependency('../../core/field_multilineinput.js', ['Blockly.FieldMultilin
goog.addDependency('../../core/field_number.js', ['Blockly.FieldNumber'], ['Blockly.FieldTextInput', 'Blockly.fieldRegistry', 'Blockly.utils.aria', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/field_registry.js', ['Blockly.fieldRegistry'], ['Blockly.registry']);
goog.addDependency('../../core/field_textinput.js', ['Blockly.FieldTextInput'], ['Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.Msg', 'Blockly.WidgetDiv', 'Blockly.browserEvents', 'Blockly.fieldRegistry', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.KeyCodes', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.userAgent']);
goog.addDependency('../../core/field_variable.js', ['Blockly.FieldVariable'], ['Blockly.Events.BlockChange', 'Blockly.FieldDropdown', 'Blockly.Msg', 'Blockly.VariableModel', 'Blockly.Variables', 'Blockly.Xml', 'Blockly.fieldRegistry', 'Blockly.internalConstants', 'Blockly.utils', 'Blockly.utils.Size', 'Blockly.utils.object']);
goog.addDependency('../../core/field_variable.js', ['Blockly.FieldVariable'], ['Blockly.Events.BlockChange', 'Blockly.FieldDropdown', 'Blockly.Msg', 'Blockly.VariableModel', 'Blockly.Variables', 'Blockly.Xml', 'Blockly.fieldRegistry', 'Blockly.internalConstants', 'Blockly.utils', 'Blockly.utils.Size', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/flyout_base.js', ['Blockly.Flyout'], ['Blockly.Block', 'Blockly.ComponentManager', 'Blockly.DeleteArea', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.VarCreate', 'Blockly.FlyoutMetricsManager', 'Blockly.Gesture', 'Blockly.IFlyout', 'Blockly.ScrollbarPair', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.WorkspaceSvg', 'Blockly.Xml', 'Blockly.blockRendering', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.toolbox', 'Blockly.utils.xml']);
goog.addDependency('../../core/flyout_button.js', ['Blockly.FlyoutButton'], ['Blockly.Css', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.style'], {'lang': 'es5'});
goog.addDependency('../../core/flyout_horizontal.js', ['Blockly.HorizontalFlyout'], ['Blockly.Block', 'Blockly.DropDownDiv', 'Blockly.Flyout', 'Blockly.Scrollbar', 'Blockly.WidgetDiv', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.object', 'Blockly.utils.toolbox']);