diff --git a/blocks/variables.js b/blocks/variables.js
index 1ec3825a4..1caf14834 100644
--- a/blocks/variables.js
+++ b/blocks/variables.js
@@ -103,6 +103,9 @@ Blockly.Constants.Variables.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MIXIN = {
* @this Blockly.Block
*/
customContextMenu: function(options) {
+ if(this.isInFlyout){
+ return;
+ }
// Getter blocks have the option to create a setter block, and vice versa.
if (this.type == 'variables_get') {
var opposite_type = 'variables_set';
diff --git a/blocks/variables_dynamic.js b/blocks/variables_dynamic.js
new file mode 100644
index 000000000..5d523f7e3
--- /dev/null
+++ b/blocks/variables_dynamic.js
@@ -0,0 +1,138 @@
+/**
+ * @license
+ * Visual Blocks Editor
+ *
+ * Copyright 2017 Google Inc.
+ * https://developers.google.com/blockly/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @fileoverview Variable blocks for Blockly.
+
+ * This file is scraped to extract a .json file of block definitions. The array
+ * passed to defineBlocksWithJsonArray(..) must be strict JSON: double quotes
+ * only, no outside references, no functions, no trailing commas, etc. The one
+ * exception is end-of-line comments, which the scraper will remove.
+ * @author duzc2dtw@gmail.com (Du Tian Wei)
+ */
+'use strict';
+
+goog.provide('Blockly.Constants.VariablesDynamic');
+
+goog.require('Blockly.Blocks');
+goog.require('Blockly');
+
+
+/**
+ * Common HSV hue for all blocks in this category.
+ * Should be the same as Blockly.Msg.VARIABLES_DYNAMIC_HUE.
+ * @readonly
+ */
+Blockly.Constants.VariablesDynamic.HUE = 310;
+
+Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
+ // Block for variable getter.
+ {
+ "type": "variables_get_dynamic",
+ "message0": "%1",
+ "args0": [{
+ "type": "field_variable",
+ "name": "VAR",
+ "variable": "%{BKY_VARIABLES_DEFAULT_NAME}"
+ }],
+ "output": null,
+ "colour": "%{BKY_VARIABLES_DYNAMIC_HUE}",
+ "helpUrl": "%{BKY_VARIABLES_GET_HELPURL}",
+ "tooltip": "%{BKY_VARIABLES_GET_TOOLTIP}",
+ "extensions": ["contextMenu_variableDynamicSetterGetter"]
+ },
+ // Block for variable setter.
+ {
+ "type": "variables_set_dynamic",
+ "message0": "%{BKY_VARIABLES_SET}",
+ "args0": [{
+ "type": "field_variable",
+ "name": "VAR",
+ "variable": "%{BKY_VARIABLES_DEFAULT_NAME}"
+ },
+ {
+ "type": "input_value",
+ "name": "VALUE"
+ }
+ ],
+ "previousStatement": null,
+ "nextStatement": null,
+ "colour": "%{BKY_VARIABLES_DYNAMIC_HUE}",
+ "tooltip": "%{BKY_VARIABLES_SET_TOOLTIP}",
+ "helpUrl": "%{BKY_VARIABLES_SET_HELPURL}",
+ "extensions": ["contextMenu_variableDynamicSetterGetter"]
+ }
+]); // END JSON EXTRACT (Do not delete this comment.)
+
+/**
+ * Mixin to add context menu items to create getter/setter blocks for this
+ * setter/getter.
+ * Used by blocks 'variables_set_dynamic' and 'variables_get_dynamic'.
+ * @mixin
+ * @augments Blockly.Block
+ * @package
+ * @readonly
+ */
+Blockly.Constants.VariablesDynamic.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MIXIN = {
+ /**
+ * Add menu option to create getter/setter block for this setter/getter.
+ * @param {!Array} options List of menu options to add to.
+ * @this Blockly.Block
+ */
+ customContextMenu: function(options) {
+ // Getter blocks have the option to create a setter block, and vice versa.
+ if(this.isInFlyout){
+ return;
+ }
+ var opposite_type ;
+ var contextMenuMsg ;
+ if (this.type == 'variables_get_dynamic') {
+ opposite_type = 'variables_set_dynamic';
+ contextMenuMsg = Blockly.Msg.VARIABLES_GET_CREATE_SET;
+ } else {
+ opposite_type = 'variables_get_dynamic';
+ contextMenuMsg = Blockly.Msg.VARIABLES_SET_CREATE_GET;
+ }
+
+ var option = { enabled: this.workspace.remainingCapacity() > 0 };
+ var name = this.getFieldValue('VAR');
+ option.text = contextMenuMsg.replace('%1', name);
+ var xmlField = goog.dom.createDom('field', null, name);
+ xmlField.setAttribute('name', 'VAR');
+ var variableModel = this.workspace.getVariable(name);
+ xmlField.setAttribute('variabletype', variableModel.type);
+ var xmlBlock = goog.dom.createDom('block', null, xmlField);
+ xmlBlock.setAttribute('type', opposite_type);
+ option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock);
+ options.push(option);
+ },
+ onchange: function() {
+ var name = this.getFieldValue('VAR');
+ var variableModel = this.workspace.getVariable(name);
+ if (this.type == 'variables_get_dynamic') {
+ this.outputConnection.setCheck(variableModel.type);
+ } else {
+ this.getInput('VALUE').connection.setCheck(variableModel.type);
+ }
+ }
+};
+
+Blockly.Extensions.registerMixin('contextMenu_variableDynamicSetterGetter',
+ Blockly.Constants.VariablesDynamic.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MIXIN);
diff --git a/core/constants.js b/core/constants.js
index f5428ff74..54ed1fb49 100644
--- a/core/constants.js
+++ b/core/constants.js
@@ -241,6 +241,13 @@ Blockly.DELETE_AREA_TOOLBOX = 2;
* @const {string}
*/
Blockly.VARIABLE_CATEGORY_NAME = 'VARIABLE';
+/**
+ * String for use in the "custom" attribute of a category in toolbox xml.
+ * This string indicates that the category should be dynamically populated with
+ * variable blocks.
+ * @const {string}
+ */
+Blockly.VARIABLE_DYNAMIC_CATEGORY_NAME = 'VARIABLE_DYNAMIC';
/**
* String for use in the "custom" attribute of a category in toolbox xml.
diff --git a/core/field_variable.js b/core/field_variable.js
index 3fa227c39..4dc071ec0 100644
--- a/core/field_variable.js
+++ b/core/field_variable.js
@@ -73,8 +73,8 @@ Blockly.FieldVariable.prototype.initModel = function() {
// Variables without names get uniquely named for this workspace.
var workspace =
this.sourceBlock_.isInFlyout ?
- this.sourceBlock_.workspace.targetWorkspace :
- this.sourceBlock_.workspace;
+ this.sourceBlock_.workspace.targetWorkspace :
+ this.sourceBlock_.workspace;
this.setValue(Blockly.Variables.generateUniqueName(workspace));
}
// If the selected variable doesn't exist yet, create it.
@@ -91,7 +91,7 @@ Blockly.FieldVariable.prototype.initModel = function() {
*/
Blockly.FieldVariable.prototype.setSourceBlock = function(block) {
goog.asserts.assert(!block.isShadow(),
- 'Variable fields are not allowed to exist on shadow blocks.');
+ 'Variable fields are not allowed to exist on shadow blocks.');
Blockly.FieldVariable.superClass_.setSourceBlock.call(this, block);
};
@@ -124,7 +124,7 @@ Blockly.FieldVariable.prototype.setValue = function(value) {
}
if (Blockly.Events.isEnabled()) {
Blockly.Events.fire(new Blockly.Events.BlockChange(
- this.sourceBlock_, 'field', this.name, this.value_, newValue));
+ this.sourceBlock_, 'field', this.name, this.value_, newValue));
}
}
this.value_ = newValue;
@@ -139,7 +139,7 @@ Blockly.FieldVariable.prototype.setValue = function(value) {
*/
Blockly.FieldVariable.prototype.getVariableTypes_ = function() {
var variableTypes = this.variableTypes;
- if (variableTypes === null) {
+ if (variableTypes === null || variableTypes === undefined) {
// If variableTypes is null, return all variable types.
if (this.sourceBlock_) {
var workspace = this.sourceBlock_.workspace;
@@ -203,7 +203,7 @@ Blockly.FieldVariable.dropdownCreate = function() {
options.push([Blockly.Msg.RENAME_VARIABLE, Blockly.RENAME_VARIABLE_ID]);
if (Blockly.Msg.DELETE_VARIABLE) {
options.push([Blockly.Msg.DELETE_VARIABLE.replace('%1', name),
- Blockly.DELETE_VARIABLE_ID]);
+ Blockly.DELETE_VARIABLE_ID]);
}
return options;
};
diff --git a/core/variables_dynamic.js b/core/variables_dynamic.js
new file mode 100644
index 000000000..fb114fae0
--- /dev/null
+++ b/core/variables_dynamic.js
@@ -0,0 +1,116 @@
+/**
+ * @license
+ * Visual Blocks Editor
+ *
+ * Copyright 2017 Google Inc.
+ * https://developers.google.com/blockly/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @fileoverview Utility functions for handling variables dynamic.
+ *
+ * @author duzc2dtw@gmail.com (Du Tian Wei)
+ */
+'use strict';
+
+goog.provide('Blockly.VariablesDynamic');
+
+goog.require('Blockly.Variables');
+goog.require('Blockly.Blocks');
+goog.require('Blockly.constants');
+goog.require('Blockly.VariableModel');
+goog.require('Blockly.Workspace');
+goog.require('goog.string');
+
+
+Blockly.VariablesDynamic.onCreateVariableButtonClick_String = function(button) {
+ Blockly.Variables.createVariable(button.getTargetWorkspace(), null, 'String');
+};
+Blockly.VariablesDynamic.onCreateVariableButtonClick_Number = function(button) {
+ Blockly.Variables.createVariable(button.getTargetWorkspace(), null, 'Number');
+};
+Blockly.VariablesDynamic.onCreateVariableButtonClick_Colour = function(button) {
+ Blockly.Variables.createVariable(button.getTargetWorkspace(), null, 'Colour');
+};
+/**
+ * Construct the elements (blocks and button) required by the flyout for the
+ * variable category.
+ * @param {!Blockly.Workspace} workspace The workspace contianing variables.
+ * @return {!Array.} Array of XML elements.
+ */
+Blockly.VariablesDynamic.flyoutCategory = function(workspace) {
+ var xmlList = [];
+ var button = goog.dom.createDom('button');
+ button.setAttribute('text', Blockly.Msg.NEW_STRING_VARIABLE);
+ button.setAttribute('callbackKey', 'CREATE_VARIABLE_STRING');
+ xmlList.push(button);
+ button = goog.dom.createDom('button');
+ button.setAttribute('text', Blockly.Msg.NEW_NUMBER_VARIABLE);
+ button.setAttribute('callbackKey', 'CREATE_VARIABLE_NUMBER');
+ xmlList.push(button);button = goog.dom.createDom('button');
+ button.setAttribute('text', Blockly.Msg.NEW_COLOUR_VARIABLE);
+ button.setAttribute('callbackKey', 'CREATE_VARIABLE_COLOUR');
+ xmlList.push(button);
+
+ workspace.registerButtonCallback('CREATE_VARIABLE_STRING',
+ Blockly.VariablesDynamic.onCreateVariableButtonClick_String);
+ workspace.registerButtonCallback('CREATE_VARIABLE_NUMBER',
+ Blockly.VariablesDynamic.onCreateVariableButtonClick_Number);
+ workspace.registerButtonCallback('CREATE_VARIABLE_COLOUR',
+ Blockly.VariablesDynamic.onCreateVariableButtonClick_Colour);
+
+
+ var blockList = Blockly.VariablesDynamic.flyoutCategoryBlocks(workspace);
+ xmlList = xmlList.concat(blockList);
+ return xmlList;
+};
+
+/**
+ * Construct the blocks required by the flyout for the variable category.
+ * @param {!Blockly.Workspace} workspace The workspace contianing variables.
+ * @return {!Array.} Array of XML block elements.
+ */
+Blockly.VariablesDynamic.flyoutCategoryBlocks = function(workspace) {
+ var variableModelList = workspace.getAllVariables();
+ variableModelList.sort(Blockly.VariableModel.compareByName);
+
+ var xmlList = [];
+ if (variableModelList.length > 0) {
+
+ if (Blockly.Blocks['variables_set_dynamic']) {
+ var firstVariable = variableModelList[0];
+ var gap = 24;
+ var blockText = '' +
+ '' +
+ Blockly.Variables.generateVariableFieldXml_(firstVariable) +
+ '' +
+ '';
+ var block = Blockly.Xml.textToDom(blockText).firstChild;
+ xmlList.push(block);
+ }
+ for (var i = 0, variable; variable = variableModelList[i]; i++) {
+ if (Blockly.Blocks['variables_get_dynamic']) {
+ var blockText = '' +
+ '' +
+ Blockly.Variables.generateVariableFieldXml_(variable) +
+ '' +
+ '';
+ var block = Blockly.Xml.textToDom(blockText).firstChild;
+ xmlList.push(block);
+ }
+ }
+ }
+ return xmlList;
+};
diff --git a/core/workspace_svg.js b/core/workspace_svg.js
index b5954b1f1..35510628b 100644
--- a/core/workspace_svg.js
+++ b/core/workspace_svg.js
@@ -104,6 +104,8 @@ Blockly.WorkspaceSvg = function(options, opt_blockDragSurface, opt_wsDragSurface
this.registerToolboxCategoryCallback(Blockly.VARIABLE_CATEGORY_NAME,
Blockly.Variables.flyoutCategory);
+ this.registerToolboxCategoryCallback(Blockly.VARIABLE_DYNAMIC_CATEGORY_NAME,
+ Blockly.VariablesDynamic.flyoutCategory);
this.registerToolboxCategoryCallback(Blockly.PROCEDURE_CATEGORY_NAME,
Blockly.Procedures.flyoutCategory);
};
diff --git a/msg/messages.js b/msg/messages.js
index c4a2c2d54..1cd48b8fb 100644
--- a/msg/messages.js
+++ b/msg/messages.js
@@ -62,6 +62,8 @@ Blockly.Msg.LISTS_HUE = '260';
Blockly.Msg.COLOUR_HUE = '20';
/// {{Notranslate}} Hue value for all variable blocks.
Blockly.Msg.VARIABLES_HUE = '330';
+/// {{Notranslate}} Hue value for all variable dynamic blocks.
+Blockly.Msg.VARIABLES_DYNAMIC_HUE = '310';
/// {{Notranslate}} Hue value for all procedure blocks.
Blockly.Msg.PROCEDURES_HUE = '290';
@@ -121,6 +123,14 @@ Blockly.Msg.RENAME_VARIABLE_TITLE = 'Rename all "%1" variables to:';
// Variable creation
/// button text - Text on the button used to launch the variable creation dialogue.
Blockly.Msg.NEW_VARIABLE = 'Create variable...';
+/// button text - Text on the button used to launch the variable creation dialogue.
+Blockly.Msg.NEW_STRING_VARIABLE = 'Create string variable...';
+/// button text - Text on the button used to launch the variable creation dialogue.
+Blockly.Msg.NEW_NUMBER_VARIABLE = 'Create number variable...';
+/// button text - Text on the button used to launch the variable creation dialogue.
+Blockly.Msg.NEW_COLOUR_VARIABLE = 'Create colour variable...';
+/// prompt - Prompts the user to enter the type for a variable.
+Blockly.Msg.NEW_VARIABLE_TYPE_TITLE = 'New variable type:';
/// prompt - Prompts the user to enter the name for a new variable. See [https://github.com/google/blockly/wiki/Variables#dropdown-menu https://github.com/google/blockly/wiki/Variables#dropdown-menu].
Blockly.Msg.NEW_VARIABLE_TITLE = 'New variable name:';
/// alert - Tells the user that the name they entered is already in use.
diff --git a/tests/playground.html b/tests/playground.html
index f062bf542..1b7599717 100644
--- a/tests/playground.html
+++ b/tests/playground.html
@@ -57,6 +57,7 @@
+