field_variable.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /**
  2. * @license
  3. * Visual Blocks Editor
  4. *
  5. * Copyright 2012 Google Inc.
  6. * https://developers.google.com/blockly/
  7. *
  8. * Licensed under the Apache License, Version 2.0 (the "License");
  9. * you may not use this file except in compliance with the License.
  10. * You may obtain a copy of the License at
  11. *
  12. * http://www.apache.org/licenses/LICENSE-2.0
  13. *
  14. * Unless required by applicable law or agreed to in writing, software
  15. * distributed under the License is distributed on an "AS IS" BASIS,
  16. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17. * See the License for the specific language governing permissions and
  18. * limitations under the License.
  19. */
  20. /**
  21. * @fileoverview Variable input field.
  22. * @author fraser@google.com (Neil Fraser)
  23. */
  24. 'use strict';
  25. goog.provide('Blockly.FieldVariable');
  26. goog.require('Blockly.FieldDropdown');
  27. goog.require('Blockly.Msg');
  28. goog.require('Blockly.Variables');
  29. goog.require('goog.string');
  30. /**
  31. * Class for a variable's dropdown field.
  32. * @param {?string} varname The default name for the variable. If null,
  33. * a unique variable name will be generated.
  34. * @param {Function=} opt_validator A function that is executed when a new
  35. * option is selected. Its sole argument is the new option value.
  36. * @extends {Blockly.FieldDropdown}
  37. * @constructor
  38. */
  39. Blockly.FieldVariable = function(varname, opt_validator) {
  40. Blockly.FieldVariable.superClass_.constructor.call(this,
  41. Blockly.FieldVariable.dropdownCreate, opt_validator);
  42. this.setValue(varname || '');
  43. };
  44. goog.inherits(Blockly.FieldVariable, Blockly.FieldDropdown);
  45. /**
  46. * Install this dropdown on a block.
  47. */
  48. Blockly.FieldVariable.prototype.init = function() {
  49. if (this.fieldGroup_) {
  50. // Dropdown has already been initialized once.
  51. return;
  52. }
  53. Blockly.FieldVariable.superClass_.init.call(this);
  54. if (!this.getValue()) {
  55. // Variables without names get uniquely named for this workspace.
  56. var workspace =
  57. this.sourceBlock_.isInFlyout ?
  58. this.sourceBlock_.workspace.targetWorkspace :
  59. this.sourceBlock_.workspace;
  60. this.setValue(Blockly.Variables.generateUniqueName(workspace));
  61. }
  62. };
  63. /**
  64. * Get the variable's name (use a variableDB to convert into a real name).
  65. * Unline a regular dropdown, variables are literal and have no neutral value.
  66. * @return {string} Current text.
  67. */
  68. Blockly.FieldVariable.prototype.getValue = function() {
  69. return this.getText();
  70. };
  71. /**
  72. * Set the variable name.
  73. * @param {string} newValue New text.
  74. */
  75. Blockly.FieldVariable.prototype.setValue = function(newValue) {
  76. if (this.sourceBlock_ && Blockly.Events.isEnabled()) {
  77. Blockly.Events.fire(new Blockly.Events.Change(
  78. this.sourceBlock_, 'field', this.name, this.value_, newValue));
  79. }
  80. this.value_ = newValue;
  81. this.setText(newValue);
  82. };
  83. /**
  84. * Return a sorted list of variable names for variable dropdown menus.
  85. * Include a special option at the end for creating a new variable name.
  86. * @return {!Array.<string>} Array of variable names.
  87. * @this {!Blockly.FieldVariable}
  88. */
  89. Blockly.FieldVariable.dropdownCreate = function() {
  90. if (this.sourceBlock_ && this.sourceBlock_.workspace) {
  91. var variableList =
  92. Blockly.Variables.allVariables(this.sourceBlock_.workspace);
  93. } else {
  94. var variableList = [];
  95. }
  96. // Ensure that the currently selected variable is an option.
  97. var name = this.getText();
  98. if (name && variableList.indexOf(name) == -1) {
  99. variableList.push(name);
  100. }
  101. variableList.sort(goog.string.caseInsensitiveCompare);
  102. variableList.push(Blockly.Msg.RENAME_VARIABLE);
  103. variableList.push(Blockly.Msg.NEW_VARIABLE);
  104. // Variables are not language-specific, use the name as both the user-facing
  105. // text and the internal representation.
  106. var options = [];
  107. for (var i = 0; i < variableList.length; i++) {
  108. options[i] = [variableList[i], variableList[i]];
  109. }
  110. return options;
  111. };
  112. /**
  113. * Event handler for a change in variable name.
  114. * Special case the 'New variable...' and 'Rename variable...' options.
  115. * In both of these special cases, prompt the user for a new name.
  116. * @param {string} text The selected dropdown menu option.
  117. * @return {null|undefined|string} An acceptable new variable name, or null if
  118. * change is to be either aborted (cancel button) or has been already
  119. * handled (rename), or undefined if an existing variable was chosen.
  120. */
  121. Blockly.FieldVariable.prototype.classValidator = function(text) {
  122. function promptName(promptText, defaultText) {
  123. Blockly.hideChaff();
  124. var newVar = window.prompt(promptText, defaultText);
  125. // Merge runs of whitespace. Strip leading and trailing whitespace.
  126. // Beyond this, all names are legal.
  127. if (newVar) {
  128. newVar = newVar.replace(/[\s\xa0]+/g, ' ').replace(/^ | $/g, '');
  129. if (newVar == Blockly.Msg.RENAME_VARIABLE ||
  130. newVar == Blockly.Msg.NEW_VARIABLE) {
  131. // Ok, not ALL names are legal...
  132. newVar = null;
  133. }
  134. }
  135. return newVar;
  136. }
  137. var workspace = this.sourceBlock_.workspace;
  138. if (text == Blockly.Msg.RENAME_VARIABLE) {
  139. var oldVar = this.getText();
  140. text = promptName(Blockly.Msg.RENAME_VARIABLE_TITLE.replace('%1', oldVar),
  141. oldVar);
  142. if (text) {
  143. Blockly.Variables.renameVariable(oldVar, text, workspace);
  144. }
  145. return null;
  146. } else if (text == Blockly.Msg.NEW_VARIABLE) {
  147. text = promptName(Blockly.Msg.NEW_VARIABLE_TITLE, '');
  148. // Since variables are case-insensitive, ensure that if the new variable
  149. // matches with an existing variable, the new case prevails throughout.
  150. if (text) {
  151. Blockly.Variables.renameVariable(text, text, workspace);
  152. return text;
  153. }
  154. return null;
  155. }
  156. return undefined;
  157. };