diff --git a/core/field_dropdown.js b/core/field_dropdown.js index ec3dd4f5a..36b1d2513 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -105,16 +105,10 @@ Blockly.FieldDropdown.prototype.showEditor_ = function() { var thisField = this; function callback(e) { + var menu = this; var menuItem = e.target; if (menuItem) { - var value = menuItem.getValue(); - if (thisField.sourceBlock_) { - // Call any validation function, and allow it to override. - value = thisField.callValidator(value); - } - if (value !== null) { - thisField.setValue(value); - } + thisField.onItemSelected(menu, menuItem); } Blockly.WidgetDiv.hideIfOwner(thisField); } @@ -192,6 +186,22 @@ Blockly.FieldDropdown.prototype.showEditor_ = function() { menuDom.focus(); }; +/** + * Handle the selection of an item in the dropdown menu. + * @param {goog.ui.Menu} menu The Menu component clicked. + * @param {goog.ui.MenuItem} menuItem The MenuItem selected within menu. + */ +Blockly.FieldDropdown.prototype.onItemSelected = function(menu, menuItem) { + var value = menuItem.getValue(); + if (this.sourceBlock_) { + // Call any validation function, and allow it to override. + value = this.callValidator(value); + } + if (value !== null) { + this.setValue(value); + } +} + /** * Factor out common words in statically defined options. * Create prefix and/or suffix labels. diff --git a/core/field_variable.js b/core/field_variable.js index f93caa150..661c24459 100644 --- a/core/field_variable.js +++ b/core/field_variable.js @@ -48,6 +48,19 @@ Blockly.FieldVariable = function(varname, opt_validator) { }; goog.inherits(Blockly.FieldVariable, Blockly.FieldDropdown); +/** + * The menu item index for the rename variable option. + * @type {number} + */ +Blockly.FieldVariable.prototype.renameVarItemIndex_ = -1; + +/** + * The menu item index for the delete variable option. + * @type {number} + */ +Blockly.FieldVariable.prototype.deleteVarItemIndex_ = -1; + + /** * Install this dropdown on a block. */ @@ -115,7 +128,11 @@ Blockly.FieldVariable.dropdownCreate = function() { variableList.push(name); } variableList.sort(goog.string.caseInsensitiveCompare); + + this.renameVarItemIndex_ = variableList.length; variableList.push(Blockly.Msg.RENAME_VARIABLE); + + this.deleteVarItemIndex_ = variableList.length; variableList.push(Blockly.Msg.DELETE_VARIABLE.replace('%1', name)); // Variables are not language-specific, use the name as both the user-facing // text and the internal representation. @@ -127,29 +144,41 @@ Blockly.FieldVariable.dropdownCreate = function() { }; /** - * Event handler for a change in variable name. + * 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 {string} text The selected dropdown menu option. - * @return {null|undefined|string} An acceptable new variable name, or null if - * change is to be either aborted (cancel button) or has been already - * handled (rename), or undefined if an existing variable was chosen. + * @param {goog.ui.Menu} menu The Menu component clicked. + * @param {goog.ui.MenuItem} menuItem The MenuItem selected within menu. */ -Blockly.FieldVariable.prototype.classValidator = function(text) { - var workspace = this.sourceBlock_.workspace; - if (text == Blockly.Msg.RENAME_VARIABLE) { - var oldVar = this.getText(); - Blockly.hideChaff(); - text = Blockly.Variables.promptName( - Blockly.Msg.RENAME_VARIABLE_TITLE.replace('%1', oldVar), oldVar); - if (text) { - workspace.renameVariable(oldVar, text); +Blockly.FieldVariable.prototype.onItemSelected = function(menu, menuItem) { + var menuLength = menu.getChildCount(); + var itemText = menuItem.getValue(); + if (this.sourceBlock_) { + var workspace = this.sourceBlock_.workspace; + if (this.renameVarItemIndex_ >= 0 && + menu.getChildAt(this.renameVarItemIndex_) === menuItem) { + // Rename variable + var oldName = this.getText(); + Blockly.hideChaff(); + Blockly.Variables.promptName( + Blockly.Msg.RENAME_VARIABLE_TITLE.replace('%1', oldName), oldName, + function(newName) { + if (newName) { + workspace.renameVariable(oldName, newName); + } + }); + return; + } else if (this.deleteVarItemIndex_ >= 0 && + menu.getChildAt(this.deleteVarItemIndex_) === menuItem) { + // Delete variable + workspace.deleteVariable(this.getText()); + return; } - return null; - } else if (text == Blockly.Msg.DELETE_VARIABLE.replace('%1', - this.getText())) { - workspace.deleteVariable(this.getText()); - return null; + + // Call any validation function, and allow it to override. + itemText = this.callValidator(itemText); + } + if (itemText !== null) { + this.setValue(itemText); } - return undefined; }; diff --git a/core/workspace.js b/core/workspace.js index 113df8baf..7d4723474 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -301,36 +301,44 @@ Blockly.Workspace.prototype.getVariableUses = function(name) { * @param {string} name Name of variable to delete. */ Blockly.Workspace.prototype.deleteVariable = function(name) { + var workspace = this; var variableIndex = this.variableIndexOf(name); if (variableIndex != -1) { + // Check whether this variable is a function parameter before deleting. var uses = this.getVariableUses(name); - if (uses.length > 1) { - 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; - } + 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; + } + + function doDeletion() { + Blockly.Events.setGroup(true); + for (var i = 0; i < uses.length; i++) { + uses[i].dispose(true, false); + } + Blockly.Events.setGroup(false); + workspace.variableList.splice(variableIndex, 1); + } + if (uses.length > 1) { + // Confirm before deleting multiple blocks. Blockly.confirm( Blockly.Msg.DELETE_VARIABLE_CONFIRMATION.replace('%1', uses.length). replace('%2', name), function(ok) { - if (!ok) { - return; + if (ok) { + doDeletion(); } - - Blockly.Events.setGroup(true); - for (var i = 0; i < uses.length; i++) { - uses[i].dispose(true, false); - } - Blockly.Events.setGroup(false); - workspace.variableList.splice(variableIndex, 1); }); + } else { + // No confirmation necessary for a single block. + doDeletion(); } } }; diff --git a/demos/mirror/index.html b/demos/mirror/index.html index 0afd27618..ea029e38d 100644 --- a/demos/mirror/index.html +++ b/demos/mirror/index.html @@ -45,6 +45,9 @@ + i + j + k