diff --git a/core/variable_events.js b/core/variable_events.js index 8e39ead8..0dcabce7 100644 --- a/core/variable_events.js +++ b/core/variable_events.js @@ -89,6 +89,7 @@ Blockly.Events.VarCreate = function(variable) { this.varType = variable.type; this.varName = variable.name; this.isLocal = variable.isLocal; + this.isCloud = variable.isCloud; }; goog.inherits(Blockly.Events.VarCreate, Blockly.Events.VarBase); @@ -107,6 +108,7 @@ Blockly.Events.VarCreate.prototype.toJson = function() { json['varType'] = this.varType; json['varName'] = this.varName; json['isLocal'] = this.isLocal; + json['isCloud'] = this.isCloud; return json; }; @@ -119,6 +121,7 @@ Blockly.Events.VarCreate.prototype.fromJson = function(json) { this.varType = json['varType']; this.varName = json['varName']; this.isLocal = json['isLocal']; + this.isCloud = json['isCloud']; }; /** @@ -128,7 +131,7 @@ Blockly.Events.VarCreate.prototype.fromJson = function(json) { Blockly.Events.VarCreate.prototype.run = function(forward) { var workspace = this.getEventWorkspace_(); if (forward) { - workspace.createVariable(this.varName, this.varType, this.varId, this.isLocal); + workspace.createVariable(this.varName, this.varType, this.varId, this.isLocal, this.isCloud); } else { workspace.deleteVariableById(this.varId); } @@ -149,6 +152,7 @@ Blockly.Events.VarDelete = function(variable) { this.varType = variable.type; this.varName = variable.name; this.isLocal = variable.isLocal; + this.isCloud = variable.isCloud; }; goog.inherits(Blockly.Events.VarDelete, Blockly.Events.VarBase); @@ -167,6 +171,7 @@ Blockly.Events.VarDelete.prototype.toJson = function() { json['varType'] = this.varType; json['varName'] = this.varName; json['isLocal'] = this.isLocal; + json['isCloud'] = this.isCloud; return json; }; @@ -179,6 +184,7 @@ Blockly.Events.VarDelete.prototype.fromJson = function(json) { this.varType = json['varType']; this.varName = json['varName']; this.isLocal = json['isLocal']; + this.isCloud = json['isCloud']; }; /** @@ -190,7 +196,7 @@ Blockly.Events.VarDelete.prototype.run = function(forward) { if (forward) { workspace.deleteVariableById(this.varId); } else { - workspace.createVariable(this.varName, this.varType, this.varId, this.isLocal); + workspace.createVariable(this.varName, this.varType, this.varId, this.isLocal, this.isCloud); } }; diff --git a/core/variable_map.js b/core/variable_map.js index d706ca10..f391c093 100644 --- a/core/variable_map.js +++ b/core/variable_map.js @@ -175,10 +175,11 @@ Blockly.VariableMap.prototype.renameVariableWithConflict_ = function(variable, * @param {string=} opt_id The unique ID of the variable. This will default to * a UUID. * @param {boolean=} opt_isLocal Whether the variable is locally scoped. + * @param {boolean=} opt_isCloud Whether the variable is a cloud variable. * @return {?Blockly.VariableModel} The newly created variable. */ Blockly.VariableMap.prototype.createVariable = function(name, - opt_type, opt_id, opt_isLocal) { + opt_type, opt_id, opt_isLocal, opt_isCloud) { var variable = this.getVariable(name, opt_type); if (variable) { if (opt_id && variable.getId() != opt_id) { @@ -203,7 +204,7 @@ Blockly.VariableMap.prototype.createVariable = function(name, opt_type = opt_type || ''; variable = new Blockly.VariableModel(this.workspace, name, opt_type, opt_id, - opt_isLocal); + opt_isLocal, opt_isCloud); // If opt_type is not a key, create a new list. if (!this.variableMap_[opt_type]) { this.variableMap_[opt_type] = [variable]; diff --git a/core/variable_model.js b/core/variable_model.js index f4a972b8..4c62d8c6 100644 --- a/core/variable_model.js +++ b/core/variable_model.js @@ -43,10 +43,12 @@ goog.require('goog.string'); * @param {string=} opt_id The unique ID of the variable. This will default to * a UUID. * @param {boolean=} opt_isLocal Whether the variable is locally scoped. + * @param {boolean=} opt_isCloud Whether the variable is a cloud variable. * @see {Blockly.FieldVariable} * @constructor */ -Blockly.VariableModel = function(workspace, name, opt_type, opt_id, opt_isLocal) { +Blockly.VariableModel = function(workspace, name, opt_type, opt_id, + opt_isLocal, opt_isCloud) { /** * The workspace the variable is in. * @type {!Blockly.Workspace} @@ -85,6 +87,12 @@ Blockly.VariableModel = function(workspace, name, opt_type, opt_id, opt_isLocal) */ this.isLocal = opt_isLocal || false; + /** + * Whether the variable is a cloud variable. + * @package + */ + this.isCloud = opt_isCloud || false; + Blockly.Events.fire(new Blockly.Events.VarCreate(this)); }; diff --git a/core/variables.js b/core/variables.js index 1ed21ad1..9728ed14 100644 --- a/core/variables.js +++ b/core/variables.js @@ -44,6 +44,15 @@ goog.require('goog.string'); */ Blockly.Variables.NAME_TYPE = Blockly.VARIABLE_CATEGORY_NAME; +/** + * Constant prefix to differentiate cloud variable names from other types + * of variables. + * This is the \u2601 cloud unicode character followed by a space. + * @type {string} + * @package + */ +Blockly.Variables.CLOUD_PREFIX = '☁ '; + /** * Find all user-created variables that are in use in the workspace. * For use by generators. @@ -289,14 +298,16 @@ Blockly.Variables.createVariable = function(workspace, opt_callback, opt_type) { // Prompt the user to enter a name for the variable Blockly.prompt(newMsg, '', - function(text, additionalVars, scope) { + function(text, additionalVars, variableOptions) { + var scope = variableOptions.scope; var isLocal = (scope === 'local') || false; + var isCloud = variableOptions.isCloud || false; // Default to [] if additionalVars is not provided additionalVars = additionalVars || []; // Only use additionalVars for global variable creation. var additionalVarNames = isLocal ? [] : additionalVars; - var validatedText = validate(text, workspace, additionalVarNames, opt_callback); + var validatedText = validate(text, workspace, additionalVarNames, isCloud, opt_callback); if (validatedText) { // The name is valid according to the type, create the variable var potentialVarMap = workspace.getPotentialVariableMap(); @@ -311,7 +322,7 @@ Blockly.Variables.createVariable = function(workspace, opt_callback, opt_type) { opt_type, workspace, false); } if (!variable) { - variable = workspace.createVariable(validatedText, opt_type, null, isLocal); + variable = workspace.createVariable(validatedText, opt_type, null, isLocal, isCloud); } var flyout = workspace.isFlyout ? workspace : workspace.getFlyout(); @@ -346,6 +357,7 @@ Blockly.Variables.createVariable = function(workspace, opt_callback, opt_type) { * already exists. * @param {Array<string>} additionalVars A list of additional var names to check * for conflicts against. + * @param {boolean} isCloud Whether the variable is a cloud variable. * @param {function(?string=)=} opt_callback An optional function to be called on * a pre-existing variable of the user-provided name. This function is currently * only used for broadcast messages. @@ -355,7 +367,8 @@ Blockly.Variables.createVariable = function(workspace, opt_callback, opt_type) { * proceed with creating or renaming the variable. * @private */ -Blockly.Variables.nameValidator_ = function(type, text, workspace, additionalVars, opt_callback) { +Blockly.Variables.nameValidator_ = function(type, text, workspace, additionalVars, + isCloud, opt_callback) { // The validators for the different variable types require slightly different arguments. // For broadcast messages, if a broadcast message of the provided name already exists, // the validator needs to call a function that updates the selected @@ -367,10 +380,10 @@ Blockly.Variables.nameValidator_ = function(type, text, workspace, additionalVar if (type == Blockly.BROADCAST_MESSAGE_VARIABLE_TYPE) { return Blockly.Variables.validateBroadcastMessageName_(text, workspace, opt_callback); } else if (type == Blockly.LIST_VARIABLE_TYPE) { - return Blockly.Variables.validateScalarVarOrListName_(text, workspace, additionalVars, type, + return Blockly.Variables.validateScalarVarOrListName_(text, workspace, additionalVars, false, type, Blockly.Msg.LIST_ALREADY_EXISTS); } else { - return Blockly.Variables.validateScalarVarOrListName_(text, workspace, additionalVars, type, + return Blockly.Variables.validateScalarVarOrListName_(text, workspace, additionalVars, isCloud, type, Blockly.Msg.VARIABLE_ALREADY_EXISTS); } }; @@ -417,6 +430,7 @@ Blockly.Variables.validateBroadcastMessageName_ = function(name, workspace, opt_ * against. * @param {Array<string>} additionalVars A list of additional variable names to check * for conflicts against. + * @param {boolean} isCloud Whether the variable is a cloud variable. * @param {string} type The type to validate the variable as. This should be one of * Blockly.SCALAR_VARIABLE_TYPE or Blockly.LIST_VARIABLE_TYPE. * @param {string} errorMsg The type-specific error message the user should see @@ -425,12 +439,15 @@ Blockly.Variables.validateBroadcastMessageName_ = function(name, workspace, opt_ * @private */ Blockly.Variables.validateScalarVarOrListName_ = function(name, workspace, additionalVars, - type, errorMsg) { + isCloud, type, errorMsg) { // For scalar variables, we don't want leading or trailing white space name = Blockly.Variables.trimName_(name); if (!name) { return null; } + if (isCloud) { + name = Blockly.Variables.CLOUD_PREFIX + name; + } if (workspace.getVariable(name, type) || additionalVars.indexOf(name) >= 0) { // error Blockly.alert(errorMsg.replace('%1', name)); @@ -472,9 +489,13 @@ Blockly.Variables.renameVariable = function(workspace, variable, var promptText = promptMsg.replace('%1', variable.name); Blockly.prompt(promptText, '', function(newName, additionalVars) { + if (variable.isCloud && + newName.length > 0 && newName.indexOf(Blockly.Variables.CLOUD_PREFIX) == 0 ) { + newName = newName.substring(2); // The name validator will add the prefix back + } additionalVars = additionalVars || []; var additionalVarNames = variable.isLocal ? [] : additionalVars; - var validatedText = validate(newName, workspace, additionalVarNames); + var validatedText = validate(newName, workspace, additionalVarNames, variable.isCloud); if (validatedText) { workspace.renameVariableById(variable.getId(), validatedText); if (opt_callback) { diff --git a/core/workspace.js b/core/workspace.js index c6ee5725..904315dc 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -341,10 +341,12 @@ Blockly.Workspace.prototype.renameVariableById = function(id, newName) { * @param {string=} opt_id The unique ID of the variable. This will default to * a UUID. * @param {boolean=} opt_isLocal Whether the variable to create is locally scoped. + * @param {boolean=} opt_isCloud Whether the variable to create is locally scoped. * @return {?Blockly.VariableModel} The newly created variable. */ -Blockly.Workspace.prototype.createVariable = function(name, opt_type, opt_id, opt_isLocal) { - return this.variableMap_.createVariable(name, opt_type, opt_id, opt_isLocal); +Blockly.Workspace.prototype.createVariable = function(name, opt_type, opt_id, + opt_isLocal, opt_isCloud) { + return this.variableMap_.createVariable(name, opt_type, opt_id, opt_isLocal, opt_isCloud); }; /** diff --git a/core/workspace_svg.js b/core/workspace_svg.js index e2674458..f270ac1f 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -1161,14 +1161,15 @@ Blockly.WorkspaceSvg.prototype.deleteVariableById = function(id) { * @param {string=} opt_id The unique ID of the variable. This will default to * a UUID. * @param {boolean=} opt_isLocal Whether the variable is locally scoped. + * @param {boolean=} opt_isCloud Whether the variable is a cloud variable. * @return {?Blockly.VariableModel} The newly created variable. * @package */ Blockly.WorkspaceSvg.prototype.createVariable = function(name, opt_type, opt_id, - opt_isLocal) { + opt_isLocal, opt_isCloud) { var variableInMap = (this.getVariable(name, opt_type) != null); var newVar = Blockly.WorkspaceSvg.superClass_.createVariable.call( - this, name, opt_type, opt_id, opt_isLocal); + this, name, opt_type, opt_id, opt_isLocal, opt_isCloud); // For performance reasons, only refresh the the toolbox for new variables. // Variables that already exist should already be there. if (!variableInMap && (opt_type != Blockly.BROADCAST_MESSAGE_VARIABLE_TYPE)) { diff --git a/core/xml.js b/core/xml.js index 13433706..1b52d4c3 100644 --- a/core/xml.js +++ b/core/xml.js @@ -72,6 +72,7 @@ Blockly.Xml.variablesToDom = function(variableList) { element.setAttribute('type', variable.type); element.setAttribute('id', variable.getId()); element.setAttribute('islocal', variable.isLocal); + element.setAttribute('isCloud', variable.isCloud); variables.appendChild(element); } return variables; @@ -638,12 +639,13 @@ Blockly.Xml.domToVariables = function(xmlVariables, workspace) { var type = xmlChild.getAttribute('type'); var id = xmlChild.getAttribute('id'); var isLocal = xmlChild.getAttribute('islocal') == 'true'; + var isCloud = xmlChild.getAttribute('isCloud') == 'true'; var name = xmlChild.textContent; if (typeof(type) === undefined || type === null) { throw Error('Variable with id, ' + id + ' is without a type'); } - workspace.createVariable(name, type, id, isLocal); + workspace.createVariable(name, type, id, isLocal, isCloud); } };