[270] | 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 | /**
|
---|
| 22 | * @fileoverview Text blocks for Blockly.
|
---|
| 23 | * @author fraser@google.com (Neil Fraser)
|
---|
| 24 | */
|
---|
| 25 | using System;
|
---|
| 26 | using System.Linq;
|
---|
| 27 | using System.Text;
|
---|
| 28 | using Bridge;
|
---|
| 29 | using Bridge.Html5;
|
---|
| 30 | using Bridge.jQuery2;
|
---|
| 31 |
|
---|
| 32 | namespace WebMrbc
|
---|
| 33 | {
|
---|
| 34 | public class Texts
|
---|
| 35 | {
|
---|
| 36 | /**
|
---|
| 37 | * Common HSV hue for all blocks in this category.
|
---|
| 38 | */
|
---|
| 39 | public static int HUE = 160;
|
---|
| 40 | }
|
---|
| 41 |
|
---|
| 42 | public class TextBlock : Block
|
---|
| 43 | {
|
---|
| 44 | public const string type_name = "text";
|
---|
| 45 |
|
---|
| 46 | public TextBlock()
|
---|
| 47 | : base(type_name)
|
---|
| 48 | {
|
---|
| 49 | }
|
---|
| 50 |
|
---|
| 51 | /**
|
---|
| 52 | * Block for text value.
|
---|
| 53 | * @this Blockly.Block
|
---|
| 54 | */
|
---|
| 55 | public void init()
|
---|
| 56 | {
|
---|
| 57 | this.setHelpUrl(Msg.TEXT_TEXT_HELPURL);
|
---|
| 58 | this.setColour(Texts.HUE);
|
---|
| 59 | this.appendDummyInput()
|
---|
| 60 | .appendField(this.newQuote_(true))
|
---|
| 61 | .appendField(new FieldTextInput(""), "TEXT")
|
---|
| 62 | .appendField(this.newQuote_(false));
|
---|
| 63 | this.setOutput(true, "String");
|
---|
| 64 | // Assign "this" to a variable for use in the tooltip closure below.
|
---|
| 65 | var thisBlock = this;
|
---|
| 66 | // Text block is trivial. Use tooltip of parent block if it exists.
|
---|
| 67 | this.setTooltip(new Func<string>(() => {
|
---|
| 68 | var parent = thisBlock.getParent();
|
---|
| 69 | return (parent != null && parent.getInputsInline() && !String.IsNullOrEmpty(parent.tooltip)) ? parent.tooltip :
|
---|
| 70 | Msg.TEXT_TEXT_TOOLTIP;
|
---|
| 71 | }));
|
---|
| 72 | }
|
---|
| 73 |
|
---|
| 74 | /**
|
---|
| 75 | * Create an image of an open or closed quote.
|
---|
| 76 | * @param {boolean} open True if open quote, false if closed.
|
---|
| 77 | * @return {!FieldImage} The field image of the quote.
|
---|
| 78 | * @this Blockly.Block
|
---|
| 79 | * @private
|
---|
| 80 | */
|
---|
| 81 | public Field newQuote_(bool open)
|
---|
| 82 | {
|
---|
| 83 | return TextBlock.newQuote_(open, this.RTL);
|
---|
| 84 | }
|
---|
| 85 |
|
---|
| 86 | public static Field newQuote_(bool open, bool RTL)
|
---|
| 87 | {
|
---|
| 88 | string file;
|
---|
| 89 | if (open == RTL) {
|
---|
| 90 | file = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAKCAQAAAAqJXdxAAAAqUlEQVQI1z3KvUpCcRiA8ef9E4JNHhI0aFEacm1o0BsI0Slx8wa8gLauoDnoBhq7DcfWhggONDmJJgqCPA7neJ7p934EOOKOnM8Q7PDElo/4x4lFb2DmuUjcUzS3URnGib9qaPNbuXvBO3sGPHJDRG6fGVdMSeWDP2q99FQdFrz26Gu5Tq7dFMzUvbXy8KXeAj57cOklgA+u1B5AoslLtGIHQMaCVnwDnADZIFIrXsoXrgAAAABJRU5ErkJggg==";
|
---|
| 91 | }
|
---|
| 92 | else {
|
---|
| 93 | file = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAKCAQAAAAqJXdxAAAAn0lEQVQI1z3OMa5BURSF4f/cQhAKjUQhuQmFNwGJEUi0RKN5rU7FHKhpjEH3TEMtkdBSCY1EIv8r7nFX9e29V7EBAOvu7RPjwmWGH/VuF8CyN9/OAdvqIXYLvtRaNjx9mMTDyo+NjAN1HNcl9ZQ5oQMM3dgDUqDo1l8DzvwmtZN7mnD+PkmLa+4mhrxVA9fRowBWmVBhFy5gYEjKMfz9AylsaRRgGzvZAAAAAElFTkSuQmCC";
|
---|
| 94 | }
|
---|
| 95 | return new FieldImage(file, 12, 12, "\"");
|
---|
| 96 | }
|
---|
| 97 | }
|
---|
| 98 |
|
---|
| 99 | public class TextJoinBlock : Block
|
---|
| 100 | {
|
---|
| 101 | public const string type_name = "text_join";
|
---|
| 102 | internal int itemCount_;
|
---|
| 103 |
|
---|
| 104 | public TextJoinBlock()
|
---|
| 105 | : base(type_name)
|
---|
| 106 | {
|
---|
| 107 | }
|
---|
| 108 |
|
---|
| 109 | /**
|
---|
| 110 | * Block for creating a string made up of any number of elements of any type.
|
---|
| 111 | * @this Blockly.Block
|
---|
| 112 | */
|
---|
| 113 | public void init()
|
---|
| 114 | {
|
---|
| 115 | this.setHelpUrl(Msg.TEXT_JOIN_HELPURL);
|
---|
| 116 | this.setColour(Texts.HUE);
|
---|
| 117 | this.itemCount_ = 2;
|
---|
| 118 | this.updateShape_();
|
---|
| 119 | this.setOutput(true, "String");
|
---|
| 120 | this.setMutator(new Mutator(new[] { TextCreateJoinItemBlock.type_name }));
|
---|
| 121 | this.setTooltip(Msg.TEXT_JOIN_TOOLTIP);
|
---|
| 122 | }
|
---|
| 123 |
|
---|
| 124 | /**
|
---|
| 125 | * Create XML to represent number of text inputs.
|
---|
| 126 | * @return {!Element} XML storage element.
|
---|
| 127 | * @this Blockly.Block
|
---|
| 128 | */
|
---|
| 129 | public Element mutationToDom()
|
---|
| 130 | {
|
---|
| 131 | var container = Document.CreateElement("mutation");
|
---|
| 132 | container.SetAttribute("items", this.itemCount_.ToString());
|
---|
| 133 | return container;
|
---|
| 134 | }
|
---|
| 135 |
|
---|
| 136 | /**
|
---|
| 137 | * Parse XML to restore the text inputs.
|
---|
| 138 | * @param {!Element} xmlElement XML storage element.
|
---|
| 139 | * @this Blockly.Block
|
---|
| 140 | */
|
---|
| 141 | public void domToMutation(Element xmlElement)
|
---|
| 142 | {
|
---|
| 143 | var count = xmlElement.GetAttribute("items");
|
---|
| 144 | this.itemCount_ = count == null ? 0 : Script.ParseInt(count, 10);
|
---|
| 145 | this.updateShape_();
|
---|
| 146 | }
|
---|
| 147 |
|
---|
| 148 | /**
|
---|
| 149 | * Populate the mutator's dialog with this block's components.
|
---|
| 150 | * @param {!Workspace} workspace Mutator's workspace.
|
---|
| 151 | * @return {!Blockly.Block} Root block in mutator.
|
---|
| 152 | * @this Blockly.Block
|
---|
| 153 | */
|
---|
| 154 | public Block decompose(Workspace workspace)
|
---|
| 155 | {
|
---|
| 156 | var containerBlock = workspace.newBlock(TextCreateJoinContainerBlock.type_name);
|
---|
| 157 | containerBlock.initSvg();
|
---|
| 158 | var connection = containerBlock.getInput("STACK").connection;
|
---|
| 159 | for (var i = 0; i < this.itemCount_; i++) {
|
---|
| 160 | var itemBlock = workspace.newBlock(TextCreateJoinItemBlock.type_name);
|
---|
| 161 | itemBlock.initSvg();
|
---|
| 162 | connection.connect(itemBlock.previousConnection);
|
---|
| 163 | connection = itemBlock.nextConnection;
|
---|
| 164 | }
|
---|
| 165 | return containerBlock;
|
---|
| 166 | }
|
---|
| 167 |
|
---|
| 168 | /**
|
---|
| 169 | * Reconfigure this block based on the mutator dialog's components.
|
---|
| 170 | * @param {!Blockly.Block} containerBlock Root block in mutator.
|
---|
| 171 | * @this Blockly.Block
|
---|
| 172 | */
|
---|
| 173 | public void compose(Block containerBlock)
|
---|
| 174 | {
|
---|
| 175 | var itemBlock = (TextCreateJoinItemBlock)containerBlock.getInputTargetBlock("STACK");
|
---|
| 176 | // Count number of inputs.
|
---|
| 177 | var connections = new Connection[0];
|
---|
| 178 | while (itemBlock != null) {
|
---|
| 179 | connections.Push(itemBlock.valueConnection_);
|
---|
| 180 | itemBlock = (itemBlock.nextConnection != null) ?
|
---|
| 181 | (TextCreateJoinItemBlock)itemBlock.nextConnection.targetBlock() : null;
|
---|
| 182 | }
|
---|
| 183 | // Disconnect any children that don"t belong.
|
---|
| 184 | for (var i = 0; i < this.itemCount_; i++) {
|
---|
| 185 | var connection = this.getInput("ADD" + i).connection.targetConnection;
|
---|
| 186 | if (connection != null && Array.IndexOf(connections, connection) == -1) {
|
---|
| 187 | connection.disconnect();
|
---|
| 188 | }
|
---|
| 189 | }
|
---|
| 190 | this.itemCount_ = connections.Length;
|
---|
| 191 | this.updateShape_();
|
---|
| 192 | // Reconnect any child blocks.
|
---|
| 193 | for (var i = 0; i < this.itemCount_; i++) {
|
---|
| 194 | Mutator.reconnect(connections[i], this, "ADD" + i);
|
---|
| 195 | }
|
---|
| 196 | }
|
---|
| 197 |
|
---|
| 198 | /**
|
---|
| 199 | * Store pointers to any connected child blocks.
|
---|
| 200 | * @param {!Blockly.Block} containerBlock Root block in mutator.
|
---|
| 201 | * @this Blockly.Block
|
---|
| 202 | */
|
---|
| 203 | public void saveConnections(Block containerBlock)
|
---|
| 204 | {
|
---|
| 205 | var itemBlock = (TextCreateJoinItemBlock)containerBlock.getInputTargetBlock("STACK");
|
---|
| 206 | var i = 0;
|
---|
| 207 | while (itemBlock != null) {
|
---|
| 208 | var input = this.getInput("ADD" + i);
|
---|
| 209 | itemBlock.valueConnection_ = (input != null) ? input.connection.targetConnection : null;
|
---|
| 210 | i++;
|
---|
| 211 | itemBlock = (itemBlock.nextConnection != null) ?
|
---|
| 212 | (TextCreateJoinItemBlock)itemBlock.nextConnection.targetBlock() : null;
|
---|
| 213 | }
|
---|
| 214 | }
|
---|
| 215 |
|
---|
| 216 | /**
|
---|
| 217 | * Modify this block to have the correct number of inputs.
|
---|
| 218 | * @private
|
---|
| 219 | * @this Blockly.Block
|
---|
| 220 | */
|
---|
| 221 | private void updateShape_()
|
---|
| 222 | {
|
---|
| 223 | if (this.itemCount_ != 0 && this.getInput("EMPTY") != null) {
|
---|
| 224 | this.removeInput("EMPTY");
|
---|
| 225 | }
|
---|
| 226 | else if (this.itemCount_ == 0 && this.getInput("EMPTY") == null) {
|
---|
| 227 | this.appendDummyInput("EMPTY")
|
---|
| 228 | .appendField(this.newQuote_(true))
|
---|
| 229 | .appendField(this.newQuote_(false));
|
---|
| 230 | }
|
---|
| 231 | // Add new inputs.
|
---|
| 232 | int i;
|
---|
| 233 | for (i = 0; i < this.itemCount_; i++) {
|
---|
| 234 | if (this.getInput("ADD" + i) == null) {
|
---|
| 235 | var input = this.appendValueInput("ADD" + i);
|
---|
| 236 | if (i == 0) {
|
---|
| 237 | input.appendField(Msg.TEXT_JOIN_TITLE_CREATEWITH);
|
---|
| 238 | }
|
---|
| 239 | }
|
---|
| 240 | }
|
---|
| 241 | // Remove deleted inputs.
|
---|
| 242 | while (this.getInput("ADD" + i) != null) {
|
---|
| 243 | this.removeInput("ADD" + i);
|
---|
| 244 | i++;
|
---|
| 245 | }
|
---|
| 246 | }
|
---|
| 247 |
|
---|
| 248 | public Field newQuote_(bool open)
|
---|
| 249 | {
|
---|
| 250 | return TextBlock.newQuote_(open, this.RTL);
|
---|
| 251 | }
|
---|
| 252 | }
|
---|
| 253 |
|
---|
| 254 | public class TextCreateJoinContainerBlock : Block
|
---|
| 255 | {
|
---|
| 256 | public const string type_name = "text_create_join_container";
|
---|
| 257 |
|
---|
| 258 | public TextCreateJoinContainerBlock()
|
---|
| 259 | : base(type_name)
|
---|
| 260 | {
|
---|
| 261 | }
|
---|
| 262 |
|
---|
| 263 | /**
|
---|
| 264 | * Mutator block for container.
|
---|
| 265 | * @this Blockly.Block
|
---|
| 266 | */
|
---|
| 267 | public void init()
|
---|
| 268 | {
|
---|
| 269 | this.setColour(Texts.HUE);
|
---|
| 270 | this.appendDummyInput()
|
---|
| 271 | .appendField(Msg.TEXT_CREATE_JOIN_TITLE_JOIN);
|
---|
| 272 | this.appendStatementInput("STACK");
|
---|
| 273 | this.setTooltip(Msg.TEXT_CREATE_JOIN_TOOLTIP);
|
---|
| 274 | this.contextMenu = false;
|
---|
| 275 | }
|
---|
| 276 | }
|
---|
| 277 |
|
---|
| 278 | [IgnoreCast]
|
---|
| 279 | public class TextCreateJoinItemBlock : Block
|
---|
| 280 | {
|
---|
| 281 | public const string type_name = "text_create_join_item";
|
---|
| 282 | public Connection valueConnection_;
|
---|
| 283 |
|
---|
| 284 | public TextCreateJoinItemBlock()
|
---|
| 285 | : base(type_name)
|
---|
| 286 | {
|
---|
| 287 | }
|
---|
| 288 |
|
---|
| 289 | /**
|
---|
| 290 | * Mutator block for add items.
|
---|
| 291 | * @this Blockly.Block
|
---|
| 292 | */
|
---|
| 293 | public void init()
|
---|
| 294 | {
|
---|
| 295 | this.setColour(Texts.HUE);
|
---|
| 296 | this.appendDummyInput()
|
---|
| 297 | .appendField(Msg.TEXT_CREATE_JOIN_ITEM_TITLE_ITEM);
|
---|
| 298 | this.setPreviousStatement(true);
|
---|
| 299 | this.setNextStatement(true);
|
---|
| 300 | this.setTooltip(Msg.TEXT_CREATE_JOIN_ITEM_TOOLTIP);
|
---|
| 301 | this.contextMenu = false;
|
---|
| 302 | }
|
---|
| 303 | }
|
---|
| 304 |
|
---|
| 305 | public class TextAppendBlock : Block
|
---|
| 306 | {
|
---|
| 307 | public const string type_name = "text_append";
|
---|
| 308 |
|
---|
| 309 | public TextAppendBlock()
|
---|
| 310 | : base(type_name)
|
---|
| 311 | {
|
---|
| 312 | }
|
---|
| 313 |
|
---|
| 314 | /**
|
---|
| 315 | * Block for appending to a variable in place.
|
---|
| 316 | * @this Blockly.Block
|
---|
| 317 | */
|
---|
| 318 | public void init()
|
---|
| 319 | {
|
---|
| 320 | this.setHelpUrl(Msg.TEXT_APPEND_HELPURL);
|
---|
| 321 | this.setColour(Texts.HUE);
|
---|
| 322 | this.appendValueInput("TEXT")
|
---|
| 323 | .appendField(Msg.TEXT_APPEND_TO)
|
---|
| 324 | .appendField(new FieldVariable(
|
---|
| 325 | Msg.TEXT_APPEND_VARIABLE), "VAR")
|
---|
| 326 | .appendField(Msg.TEXT_APPEND_APPENDTEXT);
|
---|
| 327 | this.setPreviousStatement(true);
|
---|
| 328 | this.setNextStatement(true);
|
---|
| 329 | // Assign "this" to a variable for use in the tooltip closure below.
|
---|
| 330 | var thisBlock = this;
|
---|
| 331 | this.setTooltip(new Func<string>(() => {
|
---|
| 332 | return Msg.TEXT_APPEND_TOOLTIP.Replace("%1", thisBlock.getFieldValue("VAR"));
|
---|
| 333 | }));
|
---|
| 334 | }
|
---|
| 335 | }
|
---|
| 336 |
|
---|
| 337 | public class TextLengthBlock : Block
|
---|
| 338 | {
|
---|
| 339 | public const string type_name = "text_length";
|
---|
| 340 |
|
---|
| 341 | public TextLengthBlock()
|
---|
| 342 | : base(type_name)
|
---|
| 343 | {
|
---|
| 344 | }
|
---|
| 345 |
|
---|
| 346 | /**
|
---|
| 347 | * Block for string length.
|
---|
| 348 | * @this Blockly.Block
|
---|
| 349 | */
|
---|
| 350 | public void init()
|
---|
| 351 | {
|
---|
| 352 | this.jsonInit(new {
|
---|
| 353 | message0 = Msg.TEXT_LENGTH_TITLE,
|
---|
| 354 | args0 = new object[] {
|
---|
| 355 | new {
|
---|
| 356 | type = "input_value",
|
---|
| 357 | name = "VALUE",
|
---|
| 358 | check = new [] { "String", "Array" }
|
---|
| 359 | }
|
---|
| 360 | },
|
---|
| 361 | output = "Number",
|
---|
| 362 | colour = Texts.HUE,
|
---|
| 363 | tooltip = Msg.TEXT_LENGTH_TOOLTIP,
|
---|
| 364 | helpUrl = Msg.TEXT_LENGTH_HELPURL
|
---|
| 365 | });
|
---|
| 366 | }
|
---|
| 367 | }
|
---|
| 368 |
|
---|
| 369 | public class TextIsEmptyBlock : Block
|
---|
| 370 | {
|
---|
| 371 | public const string type_name = "text_isEmpty";
|
---|
| 372 |
|
---|
| 373 | public TextIsEmptyBlock()
|
---|
| 374 | : base(type_name)
|
---|
| 375 | {
|
---|
| 376 | }
|
---|
| 377 |
|
---|
| 378 | /**
|
---|
| 379 | * Block for is the string null?
|
---|
| 380 | * @this Blockly.Block
|
---|
| 381 | */
|
---|
| 382 | public void init()
|
---|
| 383 | {
|
---|
| 384 | this.jsonInit(new {
|
---|
| 385 | message0 = Msg.TEXT_ISEMPTY_TITLE,
|
---|
| 386 | args0 = new object[] {
|
---|
| 387 | new {
|
---|
| 388 | type = "input_value",
|
---|
| 389 | name = "VALUE",
|
---|
| 390 | check = new [] { "String", "Array" }
|
---|
| 391 | }
|
---|
| 392 | },
|
---|
| 393 | output = "Boolean",
|
---|
| 394 | colour = Texts.HUE,
|
---|
| 395 | tooltip = Msg.TEXT_ISEMPTY_TOOLTIP,
|
---|
| 396 | helpUrl = Msg.TEXT_ISEMPTY_HELPURL
|
---|
| 397 | });
|
---|
| 398 | }
|
---|
| 399 | }
|
---|
| 400 |
|
---|
| 401 | public class TextIndexOfBlock : Block
|
---|
| 402 | {
|
---|
| 403 | public const string type_name = "text_indexOf";
|
---|
| 404 |
|
---|
| 405 | public TextIndexOfBlock()
|
---|
| 406 | : base(type_name)
|
---|
| 407 | {
|
---|
| 408 | }
|
---|
| 409 |
|
---|
| 410 | /**
|
---|
| 411 | * Block for finding a substring in the text.
|
---|
| 412 | * @this Blockly.Block
|
---|
| 413 | */
|
---|
| 414 | public void init()
|
---|
| 415 | {
|
---|
| 416 | var OPERATORS = new[] {
|
---|
| 417 | new [] {Msg.TEXT_INDEXOF_OPERATOR_FIRST, "FIRST"},
|
---|
| 418 | new [] {Msg.TEXT_INDEXOF_OPERATOR_LAST, "LAST"}
|
---|
| 419 | };
|
---|
| 420 | this.setHelpUrl(Msg.TEXT_INDEXOF_HELPURL);
|
---|
| 421 | this.setColour(Texts.HUE);
|
---|
| 422 | this.setOutput(true, "Number");
|
---|
| 423 | this.appendValueInput("VALUE")
|
---|
| 424 | .setCheck("String")
|
---|
| 425 | .appendField(Msg.TEXT_INDEXOF_INPUT_INTEXT);
|
---|
| 426 | this.appendValueInput("FIND")
|
---|
| 427 | .setCheck("String")
|
---|
| 428 | .appendField(new FieldDropdown(OPERATORS), "END");
|
---|
| 429 | if (!String.IsNullOrEmpty(Msg.TEXT_INDEXOF_TAIL)) {
|
---|
| 430 | this.appendDummyInput().appendField(Msg.TEXT_INDEXOF_TAIL);
|
---|
| 431 | }
|
---|
| 432 | this.setInputsInline(true);
|
---|
| 433 | // Assign "this" to a variable for use in the tooltip closure below.
|
---|
| 434 | var thisBlock = this;
|
---|
| 435 | this.setTooltip(new Func<string>(() => {
|
---|
| 436 | return Msg.TEXT_INDEXOF_TOOLTIP.Replace("%1",
|
---|
| 437 | thisBlock.workspace.options.oneBasedIndex ? "0" : "-1");
|
---|
| 438 | }));
|
---|
| 439 | }
|
---|
| 440 | }
|
---|
| 441 |
|
---|
| 442 | public class TextCharAtBlock : Block
|
---|
| 443 | {
|
---|
| 444 | public const string type_name = "text_charAt";
|
---|
| 445 | string[][] WHERE_OPTIONS;
|
---|
| 446 |
|
---|
| 447 | public TextCharAtBlock()
|
---|
| 448 | : base(type_name)
|
---|
| 449 | {
|
---|
| 450 | }
|
---|
| 451 |
|
---|
| 452 | /**
|
---|
| 453 | * Block for getting a character from the string.
|
---|
| 454 | * @this Blockly.Block
|
---|
| 455 | */
|
---|
| 456 | public void init()
|
---|
| 457 | {
|
---|
| 458 | this.WHERE_OPTIONS = new[] {
|
---|
| 459 | new [] {Msg.TEXT_CHARAT_FROM_START, "FROM_START"},
|
---|
| 460 | new [] {Msg.TEXT_CHARAT_FROM_END, "FROM_END"},
|
---|
| 461 | new [] {Msg.TEXT_CHARAT_FIRST, "FIRST"},
|
---|
| 462 | new [] {Msg.TEXT_CHARAT_LAST, "LAST"},
|
---|
| 463 | new [] {Msg.TEXT_CHARAT_RANDOM, "RANDOM"}
|
---|
| 464 | };
|
---|
| 465 | this.setHelpUrl(Msg.TEXT_CHARAT_HELPURL);
|
---|
| 466 | this.setColour(Texts.HUE);
|
---|
| 467 | this.setOutput(true, "String");
|
---|
| 468 | this.appendValueInput("VALUE")
|
---|
| 469 | .setCheck("String")
|
---|
| 470 | .appendField(Msg.TEXT_CHARAT_INPUT_INTEXT);
|
---|
| 471 | this.appendDummyInput("AT");
|
---|
| 472 | this.setInputsInline(true);
|
---|
| 473 | this.updateAt_(true);
|
---|
| 474 | // Assign "this" to a variable for use in the tooltip closure below.
|
---|
| 475 | var thisBlock = this;
|
---|
| 476 | this.setTooltip(new Func<string>(() => {
|
---|
| 477 | var where = thisBlock.getFieldValue("WHERE");
|
---|
| 478 | var tooltip = Msg.TEXT_CHARAT_TOOLTIP;
|
---|
| 479 | if (where == "FROM_START" || where == "FROM_END") {
|
---|
| 480 | var msg = (where == "FROM_START") ?
|
---|
| 481 | Msg.LISTS_INDEX_FROM_START_TOOLTIP :
|
---|
| 482 | Msg.LISTS_INDEX_FROM_END_TOOLTIP;
|
---|
| 483 | tooltip += " " + msg.Replace("%1",
|
---|
| 484 | thisBlock.workspace.options.oneBasedIndex ? "#1" : "#0");
|
---|
| 485 | }
|
---|
| 486 | return tooltip;
|
---|
| 487 | }));
|
---|
| 488 | }
|
---|
| 489 |
|
---|
| 490 | /**
|
---|
| 491 | * Create XML to represent whether there is an "AT" input.
|
---|
| 492 | * @return {!Element} XML storage element.
|
---|
| 493 | * @this Blockly.Block
|
---|
| 494 | */
|
---|
| 495 | public Element mutationToDom()
|
---|
| 496 | {
|
---|
| 497 | var container = Document.CreateElement("mutation");
|
---|
| 498 | var isAt = this.getInput("AT").type == Blockly.INPUT_VALUE;
|
---|
| 499 | container.SetAttribute("at", isAt.ToString());
|
---|
| 500 | return container;
|
---|
| 501 | }
|
---|
| 502 |
|
---|
| 503 | /**
|
---|
| 504 | * Parse XML to restore the "AT" input.
|
---|
| 505 | * @param {!Element} xmlElement XML storage element.
|
---|
| 506 | * @this Blockly.Block
|
---|
| 507 | */
|
---|
| 508 | public void domToMutation(Element xmlElement)
|
---|
| 509 | {
|
---|
| 510 | // Note: Until January 2013 this block did not have mutations,
|
---|
| 511 | // so "at" defaults to true.
|
---|
| 512 | var isAt = (xmlElement.GetAttribute("at") != "false");
|
---|
| 513 | this.updateAt_(isAt);
|
---|
| 514 | }
|
---|
| 515 |
|
---|
| 516 | /**
|
---|
| 517 | * Create or delete an input for the numeric index.
|
---|
| 518 | * @param {boolean} isAt True if the input should exist.
|
---|
| 519 | * @private
|
---|
| 520 | * @this Blockly.Block
|
---|
| 521 | */
|
---|
| 522 | public void updateAt_(bool isAt)
|
---|
| 523 | {
|
---|
| 524 | // Destroy old "AT" and "ORDINAL" inputs.
|
---|
| 525 | this.removeInput("AT");
|
---|
| 526 | this.removeInput("ORDINAL", true);
|
---|
| 527 | // Create either a value "AT" input or a dummy input.
|
---|
| 528 | if (isAt) {
|
---|
| 529 | this.appendValueInput("AT").setCheck("Number");
|
---|
| 530 | if (!String.IsNullOrEmpty(Msg.ORDINAL_NUMBER_SUFFIX)) {
|
---|
| 531 | this.appendDummyInput("ORDINAL")
|
---|
| 532 | .appendField(Msg.ORDINAL_NUMBER_SUFFIX);
|
---|
| 533 | }
|
---|
| 534 | }
|
---|
| 535 | else {
|
---|
| 536 | this.appendDummyInput("AT");
|
---|
| 537 | }
|
---|
| 538 | if (!String.IsNullOrEmpty(Msg.TEXT_CHARAT_TAIL)) {
|
---|
| 539 | this.removeInput("TAIL", true);
|
---|
| 540 | this.appendDummyInput("TAIL")
|
---|
| 541 | .appendField(Msg.TEXT_CHARAT_TAIL);
|
---|
| 542 | }
|
---|
| 543 | var menu = new FieldDropdown(this.WHERE_OPTIONS, (value) => {
|
---|
| 544 | var newAt = (value == "FROM_START") || (value == "FROM_END");
|
---|
| 545 | // The "isAt" variable is available due to this function being a closure.
|
---|
| 546 | if (newAt != isAt) {
|
---|
| 547 | this.updateAt_(newAt);
|
---|
| 548 | // This menu has been destroyed and replaced. Update the replacement.
|
---|
| 549 | this.setFieldValue(value, "WHERE");
|
---|
| 550 | return null;
|
---|
| 551 | }
|
---|
| 552 | return Script.Undefined;
|
---|
| 553 | });
|
---|
| 554 | this.getInput("AT").appendField(menu, "WHERE");
|
---|
| 555 | }
|
---|
| 556 | }
|
---|
| 557 |
|
---|
| 558 | public class TextGetSubstringBlock : Block
|
---|
| 559 | {
|
---|
| 560 | public const string type_name = "text_getSubstring";
|
---|
| 561 |
|
---|
| 562 | private string[][][] WHERE_OPTIONS;
|
---|
| 563 |
|
---|
| 564 | public TextGetSubstringBlock()
|
---|
| 565 | : base(type_name)
|
---|
| 566 | {
|
---|
| 567 | }
|
---|
| 568 |
|
---|
| 569 | /**
|
---|
| 570 | * Block for getting substring.
|
---|
| 571 | * @this Blockly.Block
|
---|
| 572 | */
|
---|
| 573 | public void init()
|
---|
| 574 | {
|
---|
| 575 | WHERE_OPTIONS = new[] {
|
---|
| 576 | new[] {
|
---|
| 577 | new [] {Msg.TEXT_GET_SUBSTRING_START_FROM_START, "FROM_START"},
|
---|
| 578 | new [] {Msg.TEXT_GET_SUBSTRING_START_FROM_END, "FROM_END"},
|
---|
| 579 | new [] {Msg.TEXT_GET_SUBSTRING_START_FIRST, "FIRST"}
|
---|
| 580 | },
|
---|
| 581 | new[] {
|
---|
| 582 | new [] {Msg.TEXT_GET_SUBSTRING_END_FROM_START, "FROM_START"},
|
---|
| 583 | new [] {Msg.TEXT_GET_SUBSTRING_END_FROM_END, "FROM_END"},
|
---|
| 584 | new [] {Msg.TEXT_GET_SUBSTRING_END_LAST, "LAST"}
|
---|
| 585 | }
|
---|
| 586 | };
|
---|
| 587 | this.setHelpUrl(Msg.TEXT_GET_SUBSTRING_HELPURL);
|
---|
| 588 | this.setColour(Texts.HUE);
|
---|
| 589 | this.appendValueInput("STRING")
|
---|
| 590 | .setCheck("String")
|
---|
| 591 | .appendField(Msg.TEXT_GET_SUBSTRING_INPUT_IN_TEXT);
|
---|
| 592 | this.appendDummyInput("AT1");
|
---|
| 593 | this.appendDummyInput("AT2");
|
---|
| 594 | if (!String.IsNullOrEmpty(Msg.TEXT_GET_SUBSTRING_TAIL)) {
|
---|
| 595 | this.appendDummyInput("TAIL")
|
---|
| 596 | .appendField(Msg.TEXT_GET_SUBSTRING_TAIL);
|
---|
| 597 | }
|
---|
| 598 | this.setInputsInline(true);
|
---|
| 599 | this.setOutput(true, "String");
|
---|
| 600 | this.updateAt_(1, true);
|
---|
| 601 | this.updateAt_(2, true);
|
---|
| 602 | this.setTooltip(Msg.TEXT_GET_SUBSTRING_TOOLTIP);
|
---|
| 603 | }
|
---|
| 604 |
|
---|
| 605 | /**
|
---|
| 606 | * Create XML to represent whether there are "AT" inputs.
|
---|
| 607 | * @return {!Element} XML storage element.
|
---|
| 608 | * @this Blockly.Block
|
---|
| 609 | */
|
---|
| 610 | public Element mutationToDom()
|
---|
| 611 | {
|
---|
| 612 | var container = Document.CreateElement("mutation");
|
---|
| 613 | var isAt1 = this.getInput("AT1").type == Blockly.INPUT_VALUE;
|
---|
| 614 | container.SetAttribute("at1", isAt1.ToString());
|
---|
| 615 | var isAt2 = this.getInput("AT2").type == Blockly.INPUT_VALUE;
|
---|
| 616 | container.SetAttribute("at2", isAt2.ToString());
|
---|
| 617 | return container;
|
---|
| 618 | }
|
---|
| 619 |
|
---|
| 620 | /**
|
---|
| 621 | * Parse XML to restore the "AT" inputs.
|
---|
| 622 | * @param {!Element} xmlElement XML storage element.
|
---|
| 623 | * @this Blockly.Block
|
---|
| 624 | */
|
---|
| 625 | public void domToMutation(Element xmlElement)
|
---|
| 626 | {
|
---|
| 627 | var isAt1 = (xmlElement.GetAttribute("at1") == "true");
|
---|
| 628 | var isAt2 = (xmlElement.GetAttribute("at2") == "true");
|
---|
| 629 | this.updateAt_(1, isAt1);
|
---|
| 630 | this.updateAt_(2, isAt2);
|
---|
| 631 | }
|
---|
| 632 |
|
---|
| 633 | /**
|
---|
| 634 | * Create or delete an input for a numeric index.
|
---|
| 635 | * This block has two such inputs, independant of each other.
|
---|
| 636 | * @param {number} n Specify first or second input (1 or 2).
|
---|
| 637 | * @param {boolean} isAt True if the input should exist.
|
---|
| 638 | * @private
|
---|
| 639 | * @this Blockly.Block
|
---|
| 640 | */
|
---|
| 641 | public void updateAt_(int n, bool isAt)
|
---|
| 642 | {
|
---|
| 643 | // Create or delete an input for the numeric index.
|
---|
| 644 | // Destroy old "AT" and "ORDINAL" inputs.
|
---|
| 645 | this.removeInput("AT" + n);
|
---|
| 646 | this.removeInput("ORDINAL" + n, true);
|
---|
| 647 | // Create either a value "AT" input or a dummy input.
|
---|
| 648 | if (isAt) {
|
---|
| 649 | this.appendValueInput("AT" + n).setCheck("Number");
|
---|
| 650 | if (!String.IsNullOrEmpty(Msg.ORDINAL_NUMBER_SUFFIX)) {
|
---|
| 651 | this.appendDummyInput("ORDINAL" + n)
|
---|
| 652 | .appendField(Msg.ORDINAL_NUMBER_SUFFIX);
|
---|
| 653 | }
|
---|
| 654 | }
|
---|
| 655 | else {
|
---|
| 656 | this.appendDummyInput("AT" + n);
|
---|
| 657 | }
|
---|
| 658 | // Move tail, if present, to end of block.
|
---|
| 659 | if (n == 2 && !String.IsNullOrEmpty(Msg.TEXT_GET_SUBSTRING_TAIL)) {
|
---|
| 660 | this.removeInput("TAIL", true);
|
---|
| 661 | this.appendDummyInput("TAIL")
|
---|
| 662 | .appendField(Msg.TEXT_GET_SUBSTRING_TAIL);
|
---|
| 663 | }
|
---|
| 664 | var menu = new FieldDropdown(WHERE_OPTIONS[n - 1], (value) => {
|
---|
| 665 | var newAt = (value == "FROM_START") || (value == "FROM_END");
|
---|
| 666 | // The "isAt" variable is available due to this function being a
|
---|
| 667 | // closure.
|
---|
| 668 | if (newAt != isAt) {
|
---|
| 669 | this.updateAt_(n, newAt);
|
---|
| 670 | // This menu has been destroyed and replaced.
|
---|
| 671 | // Update the replacement.
|
---|
| 672 | this.setFieldValue(value, "WHERE" + n);
|
---|
| 673 | return null;
|
---|
| 674 | }
|
---|
| 675 | return Script.Undefined;
|
---|
| 676 | });
|
---|
| 677 |
|
---|
| 678 | this.getInput("AT" + n)
|
---|
| 679 | .appendField(menu, "WHERE" + n);
|
---|
| 680 | if (n == 1) {
|
---|
| 681 | this.moveInputBefore("AT1", "AT2");
|
---|
| 682 | }
|
---|
| 683 | }
|
---|
| 684 | }
|
---|
| 685 |
|
---|
| 686 | public class TextChangeCaseBlock : Block
|
---|
| 687 | {
|
---|
| 688 | public const string type_name = "text_changeCase";
|
---|
| 689 |
|
---|
| 690 | public TextChangeCaseBlock()
|
---|
| 691 | : base(type_name)
|
---|
| 692 | {
|
---|
| 693 | }
|
---|
| 694 |
|
---|
| 695 | /**
|
---|
| 696 | * Block for changing capitalization.
|
---|
| 697 | * @this Blockly.Block
|
---|
| 698 | */
|
---|
| 699 | public void init()
|
---|
| 700 | {
|
---|
| 701 | var OPERATORS = new[] {
|
---|
| 702 | new [] {Msg.TEXT_CHANGECASE_OPERATOR_UPPERCASE, "UPPERCASE"},
|
---|
| 703 | new [] {Msg.TEXT_CHANGECASE_OPERATOR_LOWERCASE, "LOWERCASE"},
|
---|
| 704 | new [] {Msg.TEXT_CHANGECASE_OPERATOR_TITLECASE, "TITLECASE"}
|
---|
| 705 | };
|
---|
| 706 | this.setHelpUrl(Msg.TEXT_CHANGECASE_HELPURL);
|
---|
| 707 | this.setColour(Texts.HUE);
|
---|
| 708 | this.appendValueInput("TEXT")
|
---|
| 709 | .setCheck("String")
|
---|
| 710 | .appendField(new FieldDropdown(OPERATORS), "CASE");
|
---|
| 711 | this.setOutput(true, "String");
|
---|
| 712 | this.setTooltip(Msg.TEXT_CHANGECASE_TOOLTIP);
|
---|
| 713 | }
|
---|
| 714 | }
|
---|
| 715 |
|
---|
| 716 | public class TextTrimBlock : Block
|
---|
| 717 | {
|
---|
| 718 | public const string type_name = "text_trim";
|
---|
| 719 |
|
---|
| 720 | public TextTrimBlock()
|
---|
| 721 | : base(type_name)
|
---|
| 722 | {
|
---|
| 723 | }
|
---|
| 724 |
|
---|
| 725 | /**
|
---|
| 726 | * Block for trimming spaces.
|
---|
| 727 | * @this Blockly.Block
|
---|
| 728 | */
|
---|
| 729 | public void init()
|
---|
| 730 | {
|
---|
| 731 | var OPERATORS = new[] {
|
---|
| 732 | new [] {Msg.TEXT_TRIM_OPERATOR_BOTH, "BOTH"},
|
---|
| 733 | new [] {Msg.TEXT_TRIM_OPERATOR_LEFT, "LEFT"},
|
---|
| 734 | new [] {Msg.TEXT_TRIM_OPERATOR_RIGHT, "RIGHT"}
|
---|
| 735 | };
|
---|
| 736 | this.setHelpUrl(Msg.TEXT_TRIM_HELPURL);
|
---|
| 737 | this.setColour(Texts.HUE);
|
---|
| 738 | this.appendValueInput("TEXT")
|
---|
| 739 | .setCheck("String")
|
---|
| 740 | .appendField(new FieldDropdown(OPERATORS), "MODE");
|
---|
| 741 | this.setOutput(true, "String");
|
---|
| 742 | this.setTooltip(Msg.TEXT_TRIM_TOOLTIP);
|
---|
| 743 | }
|
---|
| 744 | }
|
---|
| 745 |
|
---|
| 746 | public class TextPrintBlock : Block
|
---|
| 747 | {
|
---|
| 748 | public const string type_name = "text_print";
|
---|
| 749 |
|
---|
| 750 | public TextPrintBlock()
|
---|
| 751 | : base(type_name)
|
---|
| 752 | {
|
---|
| 753 | }
|
---|
| 754 |
|
---|
| 755 | /**
|
---|
| 756 | * Block for print statement.
|
---|
| 757 | * @this Blockly.Block
|
---|
| 758 | */
|
---|
| 759 | public void init()
|
---|
| 760 | {
|
---|
| 761 | this.jsonInit(new {
|
---|
| 762 | message0 = Msg.TEXT_PRINT_TITLE,
|
---|
| 763 | args0 = new object[] {
|
---|
| 764 | new {
|
---|
| 765 | type = "input_value",
|
---|
| 766 | name = "TEXT"
|
---|
| 767 | }
|
---|
| 768 | },
|
---|
| 769 | previousStatement = (Union<string, string[]>)null,
|
---|
| 770 | nextStatement = (Union<string, string[]>)null,
|
---|
| 771 | colour = Texts.HUE,
|
---|
| 772 | tooltip = Msg.TEXT_PRINT_TOOLTIP,
|
---|
| 773 | helpUrl = Msg.TEXT_PRINT_HELPURL
|
---|
| 774 | });
|
---|
| 775 | }
|
---|
| 776 | }
|
---|
| 777 |
|
---|
| 778 | public class TextPromptExtBlock : Block
|
---|
| 779 | {
|
---|
| 780 | public const string type_name = "text_prompt_ext";
|
---|
| 781 |
|
---|
| 782 | public TextPromptExtBlock()
|
---|
| 783 | : base(type_name)
|
---|
| 784 | {
|
---|
| 785 | }
|
---|
| 786 |
|
---|
| 787 | /**
|
---|
| 788 | * Block for prompt function (external message).
|
---|
| 789 | * @this Blockly.Block
|
---|
| 790 | */
|
---|
| 791 | public void init()
|
---|
| 792 | {
|
---|
| 793 | var TYPES = new[] {
|
---|
| 794 | new [] {Msg.TEXT_PROMPT_TYPE_TEXT, "TEXT"},
|
---|
| 795 | new [] {Msg.TEXT_PROMPT_TYPE_NUMBER, "NUMBER"}
|
---|
| 796 | };
|
---|
| 797 | this.setHelpUrl(Msg.TEXT_PROMPT_HELPURL);
|
---|
| 798 | this.setColour(Texts.HUE);
|
---|
| 799 | // Assign "this" to a variable for use in the closures below.
|
---|
| 800 | var thisBlock = this;
|
---|
| 801 | var dropdown = new FieldDropdown(TYPES, (newOp) => {
|
---|
| 802 | thisBlock.updateType_(newOp);
|
---|
| 803 | return Script.Undefined;
|
---|
| 804 | });
|
---|
| 805 | this.appendValueInput("TEXT")
|
---|
| 806 | .appendField(dropdown, "TYPE");
|
---|
| 807 | this.setOutput(true, "String");
|
---|
| 808 | this.setTooltip(new Func<string>(() => {
|
---|
| 809 | return (thisBlock.getFieldValue("TYPE") == "TEXT") ?
|
---|
| 810 | Msg.TEXT_PROMPT_TOOLTIP_TEXT :
|
---|
| 811 | Msg.TEXT_PROMPT_TOOLTIP_NUMBER;
|
---|
| 812 | }));
|
---|
| 813 | }
|
---|
| 814 |
|
---|
| 815 | /**
|
---|
| 816 | * Modify this block to have the correct output type.
|
---|
| 817 | * @param {string} newOp Either "TEXT" or "NUMBER".
|
---|
| 818 | * @private
|
---|
| 819 | * @this Blockly.Block
|
---|
| 820 | */
|
---|
| 821 | public void updateType_(string newOp)
|
---|
| 822 | {
|
---|
| 823 | this.outputConnection.setCheck(newOp == "NUMBER" ? "Number" : "String");
|
---|
| 824 | }
|
---|
| 825 |
|
---|
| 826 | /**
|
---|
| 827 | * Create XML to represent the output type.
|
---|
| 828 | * @return {!Element} XML storage element.
|
---|
| 829 | * @this Blockly.Block
|
---|
| 830 | */
|
---|
| 831 | public Element mutationToDom()
|
---|
| 832 | {
|
---|
| 833 | var container = Document.CreateElement("mutation");
|
---|
| 834 | container.SetAttribute("type", this.getFieldValue("TYPE"));
|
---|
| 835 | return container;
|
---|
| 836 | }
|
---|
| 837 |
|
---|
| 838 | /**
|
---|
| 839 | * Parse XML to restore the output type.
|
---|
| 840 | * @param {!Element} xmlElement XML storage element.
|
---|
| 841 | * @this Blockly.Block
|
---|
| 842 | */
|
---|
| 843 | public void domToMutation(Element xmlElement)
|
---|
| 844 | {
|
---|
| 845 | this.updateType_(xmlElement.GetAttribute("type"));
|
---|
| 846 | }
|
---|
| 847 | }
|
---|
| 848 |
|
---|
| 849 | public class TextPromptBlock : Block
|
---|
| 850 | {
|
---|
| 851 | public const string type_name = "text_prompt";
|
---|
| 852 |
|
---|
| 853 | public TextPromptBlock()
|
---|
| 854 | : base(type_name)
|
---|
| 855 | {
|
---|
| 856 | }
|
---|
| 857 |
|
---|
| 858 | /**
|
---|
| 859 | * Block for prompt function (internal message).
|
---|
| 860 | * The "text_prompt_ext" block is preferred as it is more flexible.
|
---|
| 861 | * @this Blockly.Block
|
---|
| 862 | */
|
---|
| 863 | public void init()
|
---|
| 864 | {
|
---|
| 865 | var TYPES = new[] {
|
---|
| 866 | new [] {Msg.TEXT_PROMPT_TYPE_TEXT, "TEXT"},
|
---|
| 867 | new [] {Msg.TEXT_PROMPT_TYPE_NUMBER, "NUMBER"}
|
---|
| 868 | };
|
---|
| 869 | // Assign "this" to a variable for use in the closures below.
|
---|
| 870 | var thisBlock = this;
|
---|
| 871 | this.setHelpUrl(Msg.TEXT_PROMPT_HELPURL);
|
---|
| 872 | this.setColour(Texts.HUE);
|
---|
| 873 | var dropdown = new FieldDropdown(TYPES, (newOp) => {
|
---|
| 874 | thisBlock.updateType_(newOp);
|
---|
| 875 | return Script.Undefined;
|
---|
| 876 | });
|
---|
| 877 | this.appendDummyInput()
|
---|
| 878 | .appendField(dropdown, "TYPE")
|
---|
| 879 | .appendField(this.newQuote_(true))
|
---|
| 880 | .appendField(new FieldTextInput(""), "TEXT")
|
---|
| 881 | .appendField(this.newQuote_(false));
|
---|
| 882 | this.setOutput(true, "String");
|
---|
| 883 | this.setTooltip(new Func<string>(() => {
|
---|
| 884 | return (thisBlock.getFieldValue("TYPE") == "TEXT") ?
|
---|
| 885 | Msg.TEXT_PROMPT_TOOLTIP_TEXT :
|
---|
| 886 | Msg.TEXT_PROMPT_TOOLTIP_NUMBER;
|
---|
| 887 | }));
|
---|
| 888 | }
|
---|
| 889 |
|
---|
| 890 | public Field newQuote_(bool open)
|
---|
| 891 | {
|
---|
| 892 | return TextBlock.newQuote_(open, this.RTL);
|
---|
| 893 | }
|
---|
| 894 |
|
---|
| 895 | /**
|
---|
| 896 | * Modify this block to have the correct output type.
|
---|
| 897 | * @param {string} newOp Either "TEXT" or "NUMBER".
|
---|
| 898 | * @private
|
---|
| 899 | * @this Blockly.Block
|
---|
| 900 | */
|
---|
| 901 | public void updateType_(string newOp)
|
---|
| 902 | {
|
---|
| 903 | this.outputConnection.setCheck(newOp == "NUMBER" ? "Number" : "String");
|
---|
| 904 | }
|
---|
| 905 |
|
---|
| 906 | /**
|
---|
| 907 | * Create XML to represent the output type.
|
---|
| 908 | * @return {!Element} XML storage element.
|
---|
| 909 | * @this Blockly.Block
|
---|
| 910 | */
|
---|
| 911 | public Element mutationToDom()
|
---|
| 912 | {
|
---|
| 913 | var container = Document.CreateElement("mutation");
|
---|
| 914 | container.SetAttribute("type", this.getFieldValue("TYPE"));
|
---|
| 915 | return container;
|
---|
| 916 | }
|
---|
| 917 |
|
---|
| 918 | /**
|
---|
| 919 | * Parse XML to restore the output type.
|
---|
| 920 | * @param {!Element} xmlElement XML storage element.
|
---|
| 921 | * @this Blockly.Block
|
---|
| 922 | */
|
---|
| 923 | public void domToMutation(Element xmlElement)
|
---|
| 924 | {
|
---|
| 925 | this.updateType_(xmlElement.GetAttribute("type"));
|
---|
| 926 | }
|
---|
| 927 | }
|
---|
| 928 | }
|
---|