source: EcnlProtoTool/trunk/webapp/webmrbc/Blocks/Text.cs@ 270

Last change on this file since 270 was 270, checked in by coas-nagasima, 7 years ago

mruby版ECNLプロトタイピング・ツールを追加

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-csharp
File size: 24.7 KB
Line 
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 */
25using System;
26using System.Linq;
27using System.Text;
28using Bridge;
29using Bridge.Html5;
30using Bridge.jQuery2;
31
32namespace 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}
Note: See TracBrowser for help on using the repository browser.