diff --git a/blocks/text.js b/blocks/text.js
index f3c8def6a..afe8f253b 100644
--- a/blocks/text.js
+++ b/blocks/text.js
@@ -689,3 +689,90 @@ Blockly.Blocks['text_prompt'] = {
mutationToDom: Blockly.Blocks['text_prompt_ext'].mutationToDom,
domToMutation: Blockly.Blocks['text_prompt_ext'].domToMutation
};
+
+Blockly.Blocks['text_count'] = {
+ /**
+ * Block for counting how many times one string appears within another string.
+ * @this Blockly.Block
+ */
+ init: function() {
+ this.jsonInit({
+ "message0": Blockly.Msg.TEXT_COUNT_MESSAGE0,
+ "args0": [
+ {
+ "type": "input_value",
+ "name": "SUB",
+ "check": "String"
+ },
+ {
+ "type": "input_value",
+ "name": "TEXT",
+ "check": "String"
+ }
+ ],
+ "output": "Number",
+ "inputsInline": true,
+ "colour": Blockly.Blocks.math.HUE,
+ "tooltip": Blockly.Msg.TEXT_COUNT_TOOLTIP,
+ "helpUrl": Blockly.Msg.TEXT_COUNT_HELPURL
+ });
+ }
+};
+
+Blockly.Blocks['text_replace'] = {
+ /**
+ * Block for replacing one string with another in the text.
+ * @this Blockly.Block
+ */
+ init: function() {
+ this.jsonInit({
+ "message0": Blockly.Msg.TEXT_REPLACE_MESSAGE0,
+ "args0": [
+ {
+ "type": "input_value",
+ "name": "FROM",
+ "check": "String"
+ },
+ {
+ "type": "input_value",
+ "name": "TO",
+ "check": "String"
+ },
+ {
+ "type": "input_value",
+ "name": "TEXT",
+ "check": "String"
+ },
+ ],
+ "output": "String",
+ "inputsInline": true,
+ "colour": Blockly.Blocks.texts.HUE,
+ "tooltip": Blockly.Msg.TEXT_REPLACE_TOOLTIP,
+ "helpUrl": Blockly.Msg.TEXT_REPLACE_HELPURL
+ });
+ }
+};
+
+Blockly.Blocks['text_reverse'] = {
+ /**
+ * Block for reversing a string.
+ * @this Blockly.Block
+ */
+ init: function() {
+ this.jsonInit({
+ "message0": Blockly.Msg.TEXT_REVERSE_MESSAGE0,
+ "args0": [
+ {
+ "type": "input_value",
+ "name": "TEXT",
+ "check": "String"
+ },
+ ],
+ "output": "String",
+ "inputsInline": true,
+ "colour": Blockly.Blocks.texts.HUE,
+ "tooltip": Blockly.Msg.TEXT_REVERSE_TOOLTIP,
+ "helpUrl": Blockly.Msg.TEXT_REVERSE_HELPURL
+ });
+ }
+};
diff --git a/generators/dart/text.js b/generators/dart/text.js
index 47660d3bd..94c60f74b 100644
--- a/generators/dart/text.js
+++ b/generators/dart/text.js
@@ -295,3 +295,53 @@ Blockly.Dart['text_prompt_ext'] = function(block) {
};
Blockly.Dart['text_prompt'] = Blockly.Dart['text_prompt_ext'];
+
+Blockly.Dart['text_count'] = function(block) {
+ var text = Blockly.Dart.valueToCode(block, 'TEXT',
+ Blockly.Dart.ORDER_UNARY_POSTFIX) || '\'\'';
+ var sub = Blockly.Dart.valueToCode(block, 'SUB',
+ Blockly.Dart.ORDER_NONE) || '\'\'';
+ // Substring count is not a native Dart function. Define one.
+ var functionName = Blockly.Dart.provideFunction_(
+ 'text_count',
+ ['int ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ +
+ '(String haystack, String needle) {',
+ ' if (needle.length == 0) {',
+ ' return haystack.length + 1;',
+ ' }',
+ ' int index = 0;',
+ ' int count = 0;',
+ ' while (index != -1) {',
+ ' index = haystack.indexOf(needle, index);',
+ ' if (index != -1) {',
+ ' count++;',
+ ' index += needle.length;',
+ ' }',
+ ' }',
+ ' return count;',
+ '}']);
+ var code = functionName + '(' + text + ', ' + sub + ')';
+ return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
+};
+
+Blockly.Dart['text_replace'] = function(block) {
+ var text = Blockly.Dart.valueToCode(block, 'TEXT',
+ Blockly.Dart.ORDER_UNARY_POSTFIX) || '\'\'';
+ var from = Blockly.Dart.valueToCode(block, 'FROM',
+ Blockly.Dart.ORDER_NONE) || '\'\'';
+ var to = Blockly.Dart.valueToCode(block, 'TO',
+ Blockly.Dart.ORDER_NONE) || '\'\'';
+ var code = text + '.replaceAll(' + from + ', ' + to + ')';
+ return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
+};
+
+Blockly.Dart['text_reverse'] = function(block) {
+ // There isn't a sensible way to do this in Dart. See:
+ // http://stackoverflow.com/a/21613700/3529104
+ // Implementing something is possibly better than not implementing anything?
+ var text = Blockly.Dart.valueToCode(block, 'TEXT',
+ Blockly.Dart.ORDER_UNARY_POSTFIX) || '\'\'';
+ var code = 'new String.fromCharCodes(' + text + '.runes.toList().reversed)';
+ // XXX What should the operator precedence be for a `new`?
+ return [code, Blockly.Dart.ORDER_UNARY_POSTFIX];
+};
diff --git a/generators/javascript/text.js b/generators/javascript/text.js
index 3a229dc00..9e2a375a2 100644
--- a/generators/javascript/text.js
+++ b/generators/javascript/text.js
@@ -302,3 +302,51 @@ Blockly.JavaScript['text_prompt_ext'] = function(block) {
};
Blockly.JavaScript['text_prompt'] = Blockly.JavaScript['text_prompt_ext'];
+
+Blockly.JavaScript['text_count'] = function(block) {
+ var text = Blockly.JavaScript.valueToCode(block, 'TEXT',
+ Blockly.JavaScript.ORDER_MEMBER) || '\'\'';
+ var sub = Blockly.JavaScript.valueToCode(block, 'SUB',
+ Blockly.JavaScript.ORDER_NONE) || '\'\'';
+ var functionName = Blockly.JavaScript.provideFunction_(
+ 'textCount',
+ ['function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
+ '(haystack, needle) {',
+ ' if (needle.length === 0) {',
+ ' return haystack.length + 1;',
+ ' } else {',
+ ' return haystack.split(needle).length - 1;',
+ ' }',
+ '}']);
+ var code = functionName + '(' + text + ', ' + sub + ')';
+ return [code, Blockly.JavaScript.ORDER_SUBTRACTION];
+};
+
+Blockly.JavaScript['text_replace'] = function(block) {
+ var text = Blockly.JavaScript.valueToCode(block, 'TEXT',
+ Blockly.JavaScript.ORDER_MEMBER) || '\'\'';
+ var from = Blockly.JavaScript.valueToCode(block, 'FROM',
+ Blockly.JavaScript.ORDER_NONE) || '\'\'';
+ var to = Blockly.JavaScript.valueToCode(block, 'TO',
+ Blockly.JavaScript.ORDER_NONE) || '\'\'';
+ // The regex escaping code below is taken from the implementation of
+ // goog.string.regExpEscape.
+ var functionName = Blockly.JavaScript.provideFunction_(
+ 'textReplace',
+ ['function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
+ '(haystack, needle, replacement) {',
+ ' needle = ' +
+ 'needle.replace(/([-()\\[\\]{}+?*.$\\^|,:#",
- "lastupdated": "2017-01-12 13:53:04.889198",
+ "lastupdated": "2017-01-18 10:58:30.631169",
"locale": "en",
"messagedocumentation" : "qqq"
},
@@ -253,6 +253,15 @@
"TEXT_PROMPT_TYPE_NUMBER": "prompt for number with message",
"TEXT_PROMPT_TOOLTIP_NUMBER": "Prompt for user for a number.",
"TEXT_PROMPT_TOOLTIP_TEXT": "Prompt for user for some text.",
+ "TEXT_COUNT_MESSAGE0": "count %1 in %2",
+ "TEXT_COUNT_HELPURL": "",
+ "TEXT_COUNT_TOOLTIP": "Count how many times a string occurs in another string.",
+ "TEXT_REPLACE_MESSAGE0": "replace %1 with %2 in %3",
+ "TEXT_REPLACE_HELPURL": "",
+ "TEXT_REPLACE_TOOLTIP": "Replace a string within another string.",
+ "TEXT_REVERSE_MESSAGE0": "reverse %1",
+ "TEXT_REVERSE_HELPURL": "",
+ "TEXT_REVERSE_TOOLTIP": "Reverses the characters in a string.",
"LISTS_CREATE_EMPTY_HELPURL": "https://github.com/google/blockly/wiki/Lists#create-empty-list",
"LISTS_CREATE_EMPTY_TITLE": "create empty list",
"LISTS_CREATE_EMPTY_TOOLTIP": "Returns a list, of length 0, containing no data records",
diff --git a/msg/json/qqq.json b/msg/json/qqq.json
index dbb69c7cb..d37228ff9 100644
--- a/msg/json/qqq.json
+++ b/msg/json/qqq.json
@@ -1,11 +1,4 @@
{
- "@metadata": {
- "authors": [
- "Espertus",
- "Liuxinyu970226",
- "Shirayuki"
- ]
- },
"VARIABLES_DEFAULT_NAME": "default name - A simple, general default name for a variable, preferably short. For more context, see [[Translating:Blockly#infrequent_message_types]].\n{{Identical|Item}}",
"TODAY": "button text - Button that sets a calendar to today's date.\n{{Identical|Today}}",
"DUPLICATE_BLOCK": "context menu - Make a copy of the selected block (and any blocks it contains).\n{{Identical|Duplicate}}",
@@ -254,6 +247,15 @@
"TEXT_PROMPT_TYPE_NUMBER": "dropdown - Specifies that a number should be requested from the user with the following message. See [https://github.com/google/blockly/wiki/Text#printing-text https://github.com/google/blockly/wiki/Text#printing-text].",
"TEXT_PROMPT_TOOLTIP_NUMBER": "dropdown - Precedes the message with which the user should be prompted for a number. See [https://github.com/google/blockly/wiki/Text#printing-text https://github.com/google/blockly/wiki/Text#printing-text].",
"TEXT_PROMPT_TOOLTIP_TEXT": "dropdown - Precedes the message with which the user should be prompted for some text. See [https://github.com/google/blockly/wiki/Text#printing-text https://github.com/google/blockly/wiki/Text#printing-text].",
+ "TEXT_COUNT_MESSAGE0": "message0 interpolation string",
+ "TEXT_COUNT_HELPURL": "url - Information about counting how many times a string appears in another string.",
+ "TEXT_COUNT_TOOLTIP": "tooltip - See [https://github.com/google/blockly/wiki/Text#printing-text https://github.com/google/blockly/wiki/Text#printing-text].",
+ "TEXT_REPLACE_MESSAGE0": "message0 interpolation string",
+ "TEXT_REPLACE_HELPURL": "url - Information about replacing a string within another string.",
+ "TEXT_REPLACE_TOOLTIP": "tooltip - See [https://github.com/google/blockly/wiki/Text#printing-text https://github.com/google/blockly/wiki/Text#printing-text].",
+ "TEXT_REVERSE_MESSAGE0": "message0 interpolation string",
+ "TEXT_REVERSE_HELPURL": "url - Information about reversing a string.",
+ "TEXT_REVERSE_TOOLTIP": "tooltip - See [https://github.com/google/blockly/wiki/Text#printing-text https://github.com/google/blockly/wiki/Text#printing-text].",
"LISTS_CREATE_EMPTY_HELPURL": "url - Information on empty lists.",
"LISTS_CREATE_EMPTY_TITLE": "block text - See [https://github.com/google/blockly/wiki/Lists#create-empty-list https://github.com/google/blockly/wiki/Lists#create-empty-list].",
"LISTS_CREATE_EMPTY_TOOLTIP": "block text - See [https://github.com/google/blockly/wiki/Lists#create-empty-list https://github.com/google/blockly/wiki/Lists#create-empty-list].",
diff --git a/msg/messages.js b/msg/messages.js
index 24fc1fa14..a11c62d6c 100644
--- a/msg/messages.js
+++ b/msg/messages.js
@@ -766,6 +766,30 @@ Blockly.Msg.TEXT_PROMPT_TOOLTIP_NUMBER = 'Prompt for user for a number.';
/// https://github.com/google/blockly/wiki/Text#printing-text].
Blockly.Msg.TEXT_PROMPT_TOOLTIP_TEXT = 'Prompt for user for some text.';
+/// block text - Title of a block that counts the number of instances of
+/// a smaller pattern (%1) inside a longer string (%2).
+Blockly.Msg.TEXT_COUNT_MESSAGE0 = 'count %1 in %2';
+/// url - Information about counting how many times a string appears in another string.
+Blockly.Msg.TEXT_COUNT_HELPURL = 'https://github.com/google/blockly/wiki/Text#counting-substrings';
+/// tooltip - Short description of a block that counts how many times some text occurs within some other text.
+Blockly.Msg.TEXT_COUNT_TOOLTIP = 'Count how many times some text occurs within some other text.';
+
+/// block text - Title of a block that returns a copy of text (%3) with all
+/// instances of some smaller text (%1) replaced with other text (%2).
+Blockly.Msg.TEXT_REPLACE_MESSAGE0 = 'replace %1 with %2 in %3';
+/// url - Information about replacing each copy text (or string, in computer lingo) with other text.
+Blockly.Msg.TEXT_REPLACE_HELPURL = 'https://github.com/google/blockly/wiki/Text#replacing-substrings';
+/// tooltip - Short description of a block that replaces copies of text in a large text with other text.
+Blockly.Msg.TEXT_REPLACE_TOOLTIP = 'Replace all occurances of some text within some other text.';
+
+/// block text - Title of block that returns a copy of text (%1) with the order
+/// of letters and characters reversed.
+Blockly.Msg.TEXT_REVERSE_MESSAGE0 = 'reverse %1';
+/// url - Information about reversing a letters/characters in text.
+Blockly.Msg.TEXT_REVERSE_HELPURL = 'https://github.com/google/blockly/wiki/Text#reversing-text';
+/// tooltip - See [https://github.com/google/blockly/wiki/Text].
+Blockly.Msg.TEXT_REVERSE_TOOLTIP = 'Reverses the order of the characters in the text.';
+
// Lists Blocks.
/// url - Information on empty lists.
Blockly.Msg.LISTS_CREATE_EMPTY_HELPURL = 'https://github.com/google/blockly/wiki/Lists#create-empty-list';
diff --git a/tests/generators/index.html b/tests/generators/index.html
index 3f905b698..af802f2a9 100644
--- a/tests/generators/index.html
+++ b/tests/generators/index.html
@@ -280,6 +280,9 @@ h1 {
+
+
+
diff --git a/tests/generators/text.xml b/tests/generators/text.xml
index baf62d80f..32887ec93 100644
--- a/tests/generators/text.xml
+++ b/tests/generators/text.xml
@@ -1,5 +1,5 @@
-
+
@@ -36,6 +36,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -4091,4 +4106,545 @@
+
+ test count
+ Tests the "trim" block.
+
+
+ text
+
+
+ woolloomooloo
+
+
+
+
+
+
+ len 1
+
+
+
+
+
+
+ o
+
+
+
+
+ text
+
+
+
+
+
+
+ 8
+
+
+
+
+
+
+ len 2
+
+
+
+
+
+
+ oo
+
+
+
+
+ text
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+ len 3
+
+
+
+
+
+
+ loo
+
+
+
+
+ text
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+ start
+
+
+
+
+
+
+ wool
+
+
+
+
+ text
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+ missing
+
+
+
+
+
+
+ chicken
+
+
+
+
+ text
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+ empty needle
+
+
+
+
+
+
+
+
+
+
+
+ text
+
+
+
+
+
+
+ 14
+
+
+
+
+
+
+ empty source
+
+
+
+
+
+
+ chicken
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ test reverse
+ Tests the "trim" block.
+
+
+
+
+ empty string
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ len 1
+
+
+
+
+
+
+ a
+
+
+
+
+
+
+ a
+
+
+
+
+
+
+ len 2
+
+
+
+
+
+
+ ab
+
+
+
+
+
+
+ ba
+
+
+
+
+
+
+ longer
+
+
+
+
+
+
+ woolloomooloo
+
+
+
+
+
+
+ ooloomoolloow
+
+
+
+
+
+
+
+
+
+
+
+
+ test replace
+ Tests the "trim" block.
+
+
+
+
+ replace all instances 1
+
+
+
+
+
+
+ oo
+
+
+
+
+ 123
+
+
+
+
+ woolloomooloo
+
+
+
+
+
+
+ w123ll123m123l123
+
+
+
+
+
+
+ literal string replacement
+
+
+
+
+
+
+ .oo
+
+
+
+
+ X
+
+
+
+
+ woolloomooloo
+
+
+
+
+
+
+ woolloomooloo
+
+
+
+
+
+
+ not found
+
+
+
+
+
+
+ abc
+
+
+
+
+ X
+
+
+
+
+ woolloomooloo
+
+
+
+
+
+
+ woolloomooloo
+
+
+
+
+
+
+ empty replacement 1
+
+
+
+
+
+
+ o
+
+
+
+
+
+
+
+
+
+ woolloomooloo
+
+
+
+
+
+
+ wllml
+
+
+
+
+
+
+ empty replacement 2
+
+
+
+
+
+
+ aaaaa
+
+
+
+
+
+
+
+
+
+ aaaaa
+
+
+
+
+
+
+
+
+
+
+
+
+
+ empty replacement 3
+
+
+
+
+
+
+ a
+
+
+
+
+
+
+
+
+
+ aaaaa
+
+
+
+
+
+
+
+
+
+
+
+
+
+ empty source
+
+
+
+
+
+
+ a
+
+
+
+
+ chicken
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/playground.html b/tests/playground.html
index c728879e7..c05c25b81 100644
--- a/tests/playground.html
+++ b/tests/playground.html
@@ -591,6 +591,30 @@ h1 {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+