blockly 7.20211209.2 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (262) hide show
  1. package/blockly.d.ts +18963 -18432
  2. package/blockly.min.js +852 -844
  3. package/blockly_compressed.js +669 -664
  4. package/blockly_compressed.js.map +1 -1
  5. package/blocks/blocks.js +47 -0
  6. package/blocks/colour.js +13 -3
  7. package/blocks/lists.js +22 -13
  8. package/blocks/logic.js +13 -3
  9. package/blocks/loops.js +24 -11
  10. package/blocks/math.js +12 -3
  11. package/blocks/procedures.js +41 -27
  12. package/blocks/text.js +22 -13
  13. package/blocks/variables.js +14 -3
  14. package/blocks/variables_dynamic.js +13 -3
  15. package/blocks_compressed.js +146 -141
  16. package/blocks_compressed.js.map +1 -1
  17. package/core/block.js +1869 -1814
  18. package/core/block_drag_surface.js +201 -200
  19. package/core/block_dragger.js +377 -373
  20. package/core/block_svg.js +1593 -1479
  21. package/core/blockly.js +8 -22
  22. package/core/blocks.js +9 -2
  23. package/core/browser_events.js +22 -5
  24. package/core/bubble.js +841 -797
  25. package/core/bubble_dragger.js +213 -206
  26. package/core/bump_objects.js +2 -2
  27. package/core/clipboard.js +9 -9
  28. package/core/comment.js +353 -332
  29. package/core/common.js +46 -17
  30. package/core/component_manager.js +181 -174
  31. package/core/config.js +87 -0
  32. package/core/connection.js +595 -584
  33. package/core/connection_checker.js +242 -244
  34. package/core/connection_db.js +235 -230
  35. package/core/contextmenu.js +9 -6
  36. package/core/contextmenu_items.js +1 -2
  37. package/core/contextmenu_registry.js +93 -89
  38. package/core/css.js +474 -474
  39. package/core/delete_area.js +45 -42
  40. package/core/drag_target.js +57 -56
  41. package/core/dropdowndiv.js +153 -163
  42. package/core/events/events.js +2 -2
  43. package/core/events/events_abstract.js +89 -77
  44. package/core/events/events_block_base.js +37 -36
  45. package/core/events/events_block_change.js +130 -124
  46. package/core/events/events_block_create.js +73 -71
  47. package/core/events/events_block_delete.js +84 -82
  48. package/core/events/events_block_drag.js +50 -49
  49. package/core/events/events_block_move.js +147 -140
  50. package/core/events/events_bubble_open.js +51 -50
  51. package/core/events/events_click.js +48 -44
  52. package/core/events/events_comment_base.js +72 -69
  53. package/core/events/events_comment_change.js +63 -61
  54. package/core/events/events_comment_create.js +44 -42
  55. package/core/events/events_comment_delete.js +42 -40
  56. package/core/events/events_comment_move.js +106 -104
  57. package/core/events/events_marker_move.js +65 -64
  58. package/core/events/events_selected.js +46 -45
  59. package/core/events/events_theme_change.js +36 -35
  60. package/core/events/events_toolbox_item_select.js +46 -45
  61. package/core/events/events_trashcan_open.js +37 -36
  62. package/core/events/events_ui.js +47 -46
  63. package/core/events/events_ui_base.js +30 -29
  64. package/core/events/events_var_base.js +37 -36
  65. package/core/events/events_var_create.js +50 -48
  66. package/core/events/events_var_delete.js +50 -48
  67. package/core/events/events_var_rename.js +51 -49
  68. package/core/events/events_viewport.js +66 -65
  69. package/core/events/utils.js +29 -14
  70. package/core/events/workspace_events.js +49 -55
  71. package/core/extensions.js +4 -3
  72. package/core/field.js +1061 -997
  73. package/core/field_angle.js +462 -442
  74. package/core/field_checkbox.js +194 -182
  75. package/core/field_colour.js +519 -505
  76. package/core/field_dropdown.js +617 -598
  77. package/core/field_image.js +229 -220
  78. package/core/field_label.js +102 -91
  79. package/core/field_label_serializable.js +42 -41
  80. package/core/field_multilineinput.js +372 -358
  81. package/core/field_number.js +272 -253
  82. package/core/field_textinput.js +499 -467
  83. package/core/field_variable.js +458 -420
  84. package/core/flyout_base.js +1005 -952
  85. package/core/flyout_button.js +277 -260
  86. package/core/flyout_horizontal.js +304 -302
  87. package/core/flyout_metrics_manager.js +64 -64
  88. package/core/flyout_vertical.js +306 -300
  89. package/core/generator.js +459 -446
  90. package/core/gesture.js +829 -813
  91. package/core/grid.js +166 -163
  92. package/core/icon.js +168 -159
  93. package/core/inject.js +7 -5
  94. package/core/input.js +257 -248
  95. package/core/insertion_marker_manager.js +655 -624
  96. package/core/internal_constants.js +0 -129
  97. package/core/keyboard_nav/ast_node.js +605 -596
  98. package/core/keyboard_nav/basic_cursor.js +166 -165
  99. package/core/keyboard_nav/cursor.js +99 -97
  100. package/core/keyboard_nav/marker.js +83 -79
  101. package/core/keyboard_nav/tab_navigate_cursor.js +18 -23
  102. package/core/marker_manager.js +153 -141
  103. package/core/menu.js +377 -372
  104. package/core/menuitem.js +223 -217
  105. package/core/metrics_manager.js +403 -390
  106. package/core/mutator.js +468 -437
  107. package/core/names.js +229 -188
  108. package/core/options.js +290 -284
  109. package/core/procedures.js +29 -17
  110. package/core/registry.js +19 -16
  111. package/core/rendered_connection.js +482 -463
  112. package/core/renderers/common/block_rendering.js +9 -3
  113. package/core/renderers/common/constants.js +1119 -1112
  114. package/core/renderers/common/debug.js +14 -0
  115. package/core/renderers/common/debugger.js +338 -316
  116. package/core/renderers/common/drawer.js +380 -370
  117. package/core/renderers/common/i_path_object.js +2 -2
  118. package/core/renderers/common/info.js +626 -618
  119. package/core/renderers/common/marker_svg.js +579 -541
  120. package/core/renderers/common/path_object.js +203 -200
  121. package/core/renderers/common/renderer.js +220 -218
  122. package/core/renderers/geras/constants.js +36 -36
  123. package/core/renderers/geras/drawer.js +155 -147
  124. package/core/renderers/geras/highlight_constants.js +244 -238
  125. package/core/renderers/geras/highlighter.js +231 -179
  126. package/core/renderers/geras/info.js +392 -369
  127. package/core/renderers/geras/measurables/inline_input.js +25 -19
  128. package/core/renderers/geras/measurables/statement_input.js +23 -17
  129. package/core/renderers/geras/path_object.js +106 -121
  130. package/core/renderers/geras/renderer.js +96 -98
  131. package/core/renderers/measurables/base.js +30 -18
  132. package/core/renderers/measurables/bottom_row.js +83 -80
  133. package/core/renderers/measurables/connection.js +22 -15
  134. package/core/renderers/measurables/external_value_input.js +35 -22
  135. package/core/renderers/measurables/field.js +35 -20
  136. package/core/renderers/measurables/hat.js +18 -13
  137. package/core/renderers/measurables/icon.js +24 -17
  138. package/core/renderers/measurables/in_row_spacer.js +15 -13
  139. package/core/renderers/measurables/inline_input.js +43 -33
  140. package/core/renderers/measurables/input_connection.js +41 -28
  141. package/core/renderers/measurables/input_row.js +50 -44
  142. package/core/renderers/measurables/jagged_edge.js +14 -12
  143. package/core/renderers/measurables/next_connection.js +16 -14
  144. package/core/renderers/measurables/output_connection.js +26 -20
  145. package/core/renderers/measurables/previous_connection.js +16 -15
  146. package/core/renderers/measurables/round_corner.js +20 -18
  147. package/core/renderers/measurables/row.js +184 -168
  148. package/core/renderers/measurables/spacer_row.js +38 -23
  149. package/core/renderers/measurables/square_corner.js +18 -16
  150. package/core/renderers/measurables/statement_input.js +23 -20
  151. package/core/renderers/measurables/top_row.js +88 -85
  152. package/core/renderers/minimalist/constants.js +8 -7
  153. package/core/renderers/minimalist/drawer.js +11 -10
  154. package/core/renderers/minimalist/info.js +18 -18
  155. package/core/renderers/minimalist/renderer.js +40 -39
  156. package/core/renderers/thrasos/info.js +258 -248
  157. package/core/renderers/thrasos/renderer.js +20 -20
  158. package/core/renderers/zelos/constants.js +898 -873
  159. package/core/renderers/zelos/drawer.js +186 -169
  160. package/core/renderers/zelos/info.js +502 -479
  161. package/core/renderers/zelos/marker_svg.js +129 -115
  162. package/core/renderers/zelos/measurables/bottom_row.js +31 -30
  163. package/core/renderers/zelos/measurables/inputs.js +22 -21
  164. package/core/renderers/zelos/measurables/row_elements.js +14 -13
  165. package/core/renderers/zelos/measurables/top_row.js +34 -33
  166. package/core/renderers/zelos/path_object.js +181 -180
  167. package/core/renderers/zelos/renderer.js +91 -92
  168. package/core/scrollbar.js +759 -713
  169. package/core/scrollbar_pair.js +250 -245
  170. package/core/serialization/blocks.js +19 -9
  171. package/core/serialization/workspaces.js +3 -2
  172. package/core/shortcut_registry.js +286 -277
  173. package/core/sprites.js +31 -0
  174. package/core/theme.js +135 -141
  175. package/core/theme_manager.js +147 -143
  176. package/core/toolbox/category.js +602 -576
  177. package/core/toolbox/collapsible_category.js +226 -227
  178. package/core/toolbox/separator.js +70 -61
  179. package/core/toolbox/toolbox.js +934 -927
  180. package/core/toolbox/toolbox_item.js +115 -99
  181. package/core/tooltip.js +108 -35
  182. package/core/touch.js +8 -3
  183. package/core/touch_gesture.js +254 -251
  184. package/core/trashcan.js +606 -595
  185. package/core/utils/coordinate.js +97 -95
  186. package/core/utils/dom.js +2 -2
  187. package/core/utils/global.js +2 -0
  188. package/core/utils/rect.js +41 -37
  189. package/core/utils/sentinel.js +25 -0
  190. package/core/utils/size.js +30 -27
  191. package/core/utils/svg.js +18 -16
  192. package/core/variable_map.js +325 -341
  193. package/core/variable_model.js +55 -54
  194. package/core/variables.js +9 -2
  195. package/core/variables_dynamic.js +3 -1
  196. package/core/warning.js +126 -120
  197. package/core/widgetdiv.js +4 -4
  198. package/core/workspace.js +685 -664
  199. package/core/workspace_audio.js +124 -118
  200. package/core/workspace_comment.js +308 -298
  201. package/core/workspace_comment_svg.js +1029 -951
  202. package/core/workspace_drag_surface_svg.js +147 -140
  203. package/core/workspace_dragger.js +70 -71
  204. package/core/workspace_svg.js +2322 -2297
  205. package/core/xml.js +30 -20
  206. package/core/zoom_controls.js +431 -439
  207. package/dart_compressed.js +40 -43
  208. package/dart_compressed.js.map +1 -1
  209. package/generators/dart/colour.js +56 -64
  210. package/generators/dart/lists.js +61 -50
  211. package/generators/dart/math.js +160 -148
  212. package/generators/dart/text.js +83 -61
  213. package/generators/javascript/colour.js +37 -34
  214. package/generators/javascript/lists.js +50 -43
  215. package/generators/javascript/math.js +123 -139
  216. package/generators/javascript/text.js +67 -81
  217. package/generators/lua/colour.js +25 -23
  218. package/generators/lua/lists.js +97 -69
  219. package/generators/lua/logic.js +1 -2
  220. package/generators/lua/math.js +182 -144
  221. package/generators/lua/text.js +116 -99
  222. package/generators/php/colour.js +38 -32
  223. package/generators/php/lists.js +109 -89
  224. package/generators/php/math.js +90 -81
  225. package/generators/php/text.js +63 -61
  226. package/generators/python/colour.js +18 -18
  227. package/generators/python/lists.js +38 -30
  228. package/generators/python/loops.js +12 -8
  229. package/generators/python/math.js +104 -106
  230. package/generators/python/text.js +34 -30
  231. package/javascript_compressed.js +37 -39
  232. package/javascript_compressed.js.map +1 -1
  233. package/lua_compressed.js +39 -42
  234. package/lua_compressed.js.map +1 -1
  235. package/msg/az.js +2 -2
  236. package/msg/be.js +4 -4
  237. package/msg/cs.js +15 -15
  238. package/msg/de.js +1 -1
  239. package/msg/diq.js +1 -1
  240. package/msg/eo.js +1 -1
  241. package/msg/es.js +1 -1
  242. package/msg/fa.js +1 -1
  243. package/msg/fr.js +4 -4
  244. package/msg/he.js +1 -1
  245. package/msg/hr.js +2 -2
  246. package/msg/hy.js +2 -2
  247. package/msg/id.js +12 -12
  248. package/msg/inh.js +14 -14
  249. package/msg/ja.js +7 -7
  250. package/msg/lv.js +29 -29
  251. package/msg/pa.js +3 -3
  252. package/msg/smn.js +436 -0
  253. package/msg/te.js +1 -1
  254. package/msg/yue.js +1 -1
  255. package/msg/zh-hans.js +3 -3
  256. package/msg/zh-hant.js +3 -3
  257. package/package.json +7 -6
  258. package/php_compressed.js +38 -42
  259. package/php_compressed.js.map +1 -1
  260. package/python_compressed.js +26 -25
  261. package/python_compressed.js.map +1 -1
  262. package/blocks/all.js +0 -23
@@ -32,22 +32,22 @@ PHP['text_multiline'] = function(block) {
32
32
  PHP['text_join'] = function(block) {
33
33
  // Create a string made up of any number of elements of any type.
34
34
  if (block.itemCount_ === 0) {
35
- return ['\'\'', PHP.ORDER_ATOMIC];
35
+ return ["''", PHP.ORDER_ATOMIC];
36
36
  } else if (block.itemCount_ === 1) {
37
- const element = PHP.valueToCode(block, 'ADD0', PHP.ORDER_NONE) || '\'\'';
37
+ const element = PHP.valueToCode(block, 'ADD0', PHP.ORDER_NONE) || "''";
38
38
  const code = element;
39
39
  return [code, PHP.ORDER_NONE];
40
40
  } else if (block.itemCount_ === 2) {
41
41
  const element0 =
42
- PHP.valueToCode(block, 'ADD0', PHP.ORDER_STRING_CONCAT) || '\'\'';
42
+ PHP.valueToCode(block, 'ADD0', PHP.ORDER_STRING_CONCAT) || "''";
43
43
  const element1 =
44
- PHP.valueToCode(block, 'ADD1', PHP.ORDER_STRING_CONCAT) || '\'\'';
44
+ PHP.valueToCode(block, 'ADD1', PHP.ORDER_STRING_CONCAT) || "''";
45
45
  const code = element0 + ' . ' + element1;
46
46
  return [code, PHP.ORDER_STRING_CONCAT];
47
47
  } else {
48
48
  const elements = new Array(block.itemCount_);
49
49
  for (let i = 0; i < block.itemCount_; i++) {
50
- elements[i] = PHP.valueToCode(block, 'ADD' + i, PHP.ORDER_NONE) || '\'\'';
50
+ elements[i] = PHP.valueToCode(block, 'ADD' + i, PHP.ORDER_NONE) || "''";
51
51
  }
52
52
  const code = 'implode(\'\', array(' + elements.join(',') + '))';
53
53
  return [code, PHP.ORDER_FUNCTION_CALL];
@@ -58,24 +58,27 @@ PHP['text_append'] = function(block) {
58
58
  // Append to a variable in place.
59
59
  const varName =
60
60
  PHP.nameDB_.getName(block.getFieldValue('VAR'), NameType.VARIABLE);
61
- const value = PHP.valueToCode(block, 'TEXT', PHP.ORDER_ASSIGNMENT) || '\'\'';
61
+ const value = PHP.valueToCode(block, 'TEXT', PHP.ORDER_ASSIGNMENT) || "''";
62
62
  return varName + ' .= ' + value + ';\n';
63
63
  };
64
64
 
65
65
  PHP['text_length'] = function(block) {
66
66
  // String or array length.
67
- const functionName = PHP.provideFunction_('length', [
68
- 'function ' + PHP.FUNCTION_NAME_PLACEHOLDER_ + '($value) {',
69
- ' if (is_string($value)) {', ' return strlen($value);', ' } else {',
70
- ' return count($value);', ' }', '}'
71
- ]);
72
- const text = PHP.valueToCode(block, 'VALUE', PHP.ORDER_NONE) || '\'\'';
67
+ const functionName = PHP.provideFunction_('length', `
68
+ function ${PHP.FUNCTION_NAME_PLACEHOLDER_}($value) {
69
+ if (is_string($value)) {
70
+ return strlen($value);
71
+ }
72
+ return count($value);
73
+ }
74
+ `);
75
+ const text = PHP.valueToCode(block, 'VALUE', PHP.ORDER_NONE) || "''";
73
76
  return [functionName + '(' + text + ')', PHP.ORDER_FUNCTION_CALL];
74
77
  };
75
78
 
76
79
  PHP['text_isEmpty'] = function(block) {
77
80
  // Is the string null or array empty?
78
- const text = PHP.valueToCode(block, 'VALUE', PHP.ORDER_NONE) || '\'\'';
81
+ const text = PHP.valueToCode(block, 'VALUE', PHP.ORDER_NONE) || "''";
79
82
  return ['empty(' + text + ')', PHP.ORDER_FUNCTION_CALL];
80
83
  };
81
84
 
@@ -83,8 +86,8 @@ PHP['text_indexOf'] = function(block) {
83
86
  // Search the text for a substring.
84
87
  const operator =
85
88
  block.getFieldValue('END') === 'FIRST' ? 'strpos' : 'strrpos';
86
- const substring = PHP.valueToCode(block, 'FIND', PHP.ORDER_NONE) || '\'\'';
87
- const text = PHP.valueToCode(block, 'VALUE', PHP.ORDER_NONE) || '\'\'';
89
+ const substring = PHP.valueToCode(block, 'FIND', PHP.ORDER_NONE) || "''";
90
+ const text = PHP.valueToCode(block, 'VALUE', PHP.ORDER_NONE) || "''";
88
91
  let errorIndex = ' -1';
89
92
  let indexAdjustment = '';
90
93
  if (block.workspace.options.oneBasedIndex) {
@@ -94,13 +97,12 @@ PHP['text_indexOf'] = function(block) {
94
97
  const functionName = PHP.provideFunction_(
95
98
  block.getFieldValue('END') === 'FIRST' ? 'text_indexOf' :
96
99
  'text_lastIndexOf',
97
- [
98
- 'function ' + PHP.FUNCTION_NAME_PLACEHOLDER_ + '($text, $search) {',
99
- ' $pos = ' + operator + '($text, $search);',
100
- ' return $pos === false ? ' + errorIndex + ' : $pos' +
101
- indexAdjustment + ';',
102
- '}'
103
- ]);
100
+ `
101
+ function ${PHP.FUNCTION_NAME_PLACEHOLDER_}($text, $search) {
102
+ $pos = ${operator}($text, $search);
103
+ return $pos === false ? ${errorIndex} : $pos${indexAdjustment};
104
+ }
105
+ `);
104
106
  const code = functionName + '(' + text + ', ' + substring + ')';
105
107
  return [code, PHP.ORDER_FUNCTION_CALL];
106
108
  };
@@ -109,7 +111,7 @@ PHP['text_charAt'] = function(block) {
109
111
  // Get letter at index.
110
112
  const where = block.getFieldValue('WHERE') || 'FROM_START';
111
113
  const textOrder = (where === 'RANDOM') ? PHP.ORDER_NONE : PHP.ORDER_NONE;
112
- const text = PHP.valueToCode(block, 'VALUE', textOrder) || '\'\'';
114
+ const text = PHP.valueToCode(block, 'VALUE', textOrder) || "''";
113
115
  switch (where) {
114
116
  case 'FIRST': {
115
117
  const code = 'substr(' + text + ', 0, 1)';
@@ -130,10 +132,11 @@ PHP['text_charAt'] = function(block) {
130
132
  return [code, PHP.ORDER_FUNCTION_CALL];
131
133
  }
132
134
  case 'RANDOM': {
133
- const functionName = PHP.provideFunction_('text_random_letter', [
134
- 'function ' + PHP.FUNCTION_NAME_PLACEHOLDER_ + '($text) {',
135
- ' return $text[rand(0, strlen($text) - 1)];', '}'
136
- ]);
135
+ const functionName = PHP.provideFunction_('text_random_letter', `
136
+ function ${PHP.FUNCTION_NAME_PLACEHOLDER_}($text) {
137
+ return $text[rand(0, strlen($text) - 1)];
138
+ }
139
+ `);
137
140
  const code = functionName + '(' + text + ')';
138
141
  return [code, PHP.ORDER_FUNCTION_CALL];
139
142
  }
@@ -145,36 +148,35 @@ PHP['text_getSubstring'] = function(block) {
145
148
  // Get substring.
146
149
  const where1 = block.getFieldValue('WHERE1');
147
150
  const where2 = block.getFieldValue('WHERE2');
148
- const text = PHP.valueToCode(block, 'STRING', PHP.ORDER_NONE) || '\'\'';
151
+ const text = PHP.valueToCode(block, 'STRING', PHP.ORDER_NONE) || "''";
149
152
  if (where1 === 'FIRST' && where2 === 'LAST') {
150
153
  const code = text;
151
154
  return [code, PHP.ORDER_NONE];
152
155
  } else {
153
156
  const at1 = PHP.getAdjusted(block, 'AT1');
154
157
  const at2 = PHP.getAdjusted(block, 'AT2');
155
- const functionName = PHP.provideFunction_('text_get_substring', [
156
- 'function ' + PHP.FUNCTION_NAME_PLACEHOLDER_ +
157
- '($text, $where1, $at1, $where2, $at2) {',
158
- ' if ($where1 == \'FROM_END\') {',
159
- ' $at1 = strlen($text) - 1 - $at1;',
160
- ' } else if ($where1 == \'FIRST\') {',
161
- ' $at1 = 0;',
162
- ' } else if ($where1 != \'FROM_START\') {',
163
- ' throw new Exception(\'Unhandled option (text_get_substring).\');',
164
- ' }',
165
- ' $length = 0;',
166
- ' if ($where2 == \'FROM_START\') {',
167
- ' $length = $at2 - $at1 + 1;',
168
- ' } else if ($where2 == \'FROM_END\') {',
169
- ' $length = strlen($text) - $at1 - $at2;',
170
- ' } else if ($where2 == \'LAST\') {',
171
- ' $length = strlen($text) - $at1;',
172
- ' } else {',
173
- ' throw new Exception(\'Unhandled option (text_get_substring).\');',
174
- ' }',
175
- ' return substr($text, $at1, $length);',
176
- '}'
177
- ]);
158
+ const functionName = PHP.provideFunction_('text_get_substring', `
159
+ function ${PHP.FUNCTION_NAME_PLACEHOLDER_}($text, $where1, $at1, $where2, $at2) {
160
+ if ($where1 == 'FROM_END') {
161
+ $at1 = strlen($text) - 1 - $at1;
162
+ } else if ($where1 == 'FIRST') {
163
+ $at1 = 0;
164
+ } else if ($where1 != 'FROM_START') {
165
+ throw new Exception('Unhandled option (text_get_substring).');
166
+ }
167
+ $length = 0;
168
+ if ($where2 == 'FROM_START') {
169
+ $length = $at2 - $at1 + 1;
170
+ } else if ($where2 == 'FROM_END') {
171
+ $length = strlen($text) - $at1 - $at2;
172
+ } else if ($where2 == 'LAST') {
173
+ $length = strlen($text) - $at1;
174
+ } else {
175
+ throw new Exception('Unhandled option (text_get_substring).');
176
+ }
177
+ return substr($text, $at1, $length);
178
+ }
179
+ `);
178
180
  const code = functionName + '(' + text + ', \'' + where1 + '\', ' + at1 +
179
181
  ', \'' + where2 + '\', ' + at2 + ')';
180
182
  return [code, PHP.ORDER_FUNCTION_CALL];
@@ -183,7 +185,7 @@ PHP['text_getSubstring'] = function(block) {
183
185
 
184
186
  PHP['text_changeCase'] = function(block) {
185
187
  // Change capitalization.
186
- const text = PHP.valueToCode(block, 'TEXT', PHP.ORDER_NONE) || '\'\'';
188
+ const text = PHP.valueToCode(block, 'TEXT', PHP.ORDER_NONE) || "''";
187
189
  let code;
188
190
  if (block.getFieldValue('CASE') === 'UPPERCASE') {
189
191
  code = 'strtoupper(' + text + ')';
@@ -199,13 +201,13 @@ PHP['text_trim'] = function(block) {
199
201
  // Trim spaces.
200
202
  const OPERATORS = {'LEFT': 'ltrim', 'RIGHT': 'rtrim', 'BOTH': 'trim'};
201
203
  const operator = OPERATORS[block.getFieldValue('MODE')];
202
- const text = PHP.valueToCode(block, 'TEXT', PHP.ORDER_NONE) || '\'\'';
204
+ const text = PHP.valueToCode(block, 'TEXT', PHP.ORDER_NONE) || "''";
203
205
  return [operator + '(' + text + ')', PHP.ORDER_FUNCTION_CALL];
204
206
  };
205
207
 
206
208
  PHP['text_print'] = function(block) {
207
209
  // Print statement.
208
- const msg = PHP.valueToCode(block, 'TEXT', PHP.ORDER_NONE) || '\'\'';
210
+ const msg = PHP.valueToCode(block, 'TEXT', PHP.ORDER_NONE) || "''";
209
211
  return 'print(' + msg + ');\n';
210
212
  };
211
213
 
@@ -217,7 +219,7 @@ PHP['text_prompt_ext'] = function(block) {
217
219
  msg = PHP.quote_(block.getFieldValue('TEXT'));
218
220
  } else {
219
221
  // External message.
220
- msg = PHP.valueToCode(block, 'TEXT', PHP.ORDER_NONE) || '\'\'';
222
+ msg = PHP.valueToCode(block, 'TEXT', PHP.ORDER_NONE) || "''";
221
223
  }
222
224
  let code = 'readline(' + msg + ')';
223
225
  const toNumber = block.getFieldValue('TYPE') === 'NUMBER';
@@ -230,8 +232,8 @@ PHP['text_prompt_ext'] = function(block) {
230
232
  PHP['text_prompt'] = PHP['text_prompt_ext'];
231
233
 
232
234
  PHP['text_count'] = function(block) {
233
- const text = PHP.valueToCode(block, 'TEXT', PHP.ORDER_NONE) || '\'\'';
234
- const sub = PHP.valueToCode(block, 'SUB', PHP.ORDER_NONE) || '\'\'';
235
+ const text = PHP.valueToCode(block, 'TEXT', PHP.ORDER_NONE) || "''";
236
+ const sub = PHP.valueToCode(block, 'SUB', PHP.ORDER_NONE) || "''";
235
237
  const code = 'strlen(' + sub + ') === 0' +
236
238
  ' ? strlen(' + text + ') + 1' +
237
239
  ' : substr_count(' + text + ', ' + sub + ')';
@@ -239,15 +241,15 @@ PHP['text_count'] = function(block) {
239
241
  };
240
242
 
241
243
  PHP['text_replace'] = function(block) {
242
- const text = PHP.valueToCode(block, 'TEXT', PHP.ORDER_NONE) || '\'\'';
243
- const from = PHP.valueToCode(block, 'FROM', PHP.ORDER_NONE) || '\'\'';
244
- const to = PHP.valueToCode(block, 'TO', PHP.ORDER_NONE) || '\'\'';
244
+ const text = PHP.valueToCode(block, 'TEXT', PHP.ORDER_NONE) || "''";
245
+ const from = PHP.valueToCode(block, 'FROM', PHP.ORDER_NONE) || "''";
246
+ const to = PHP.valueToCode(block, 'TO', PHP.ORDER_NONE) || "''";
245
247
  const code = 'str_replace(' + from + ', ' + to + ', ' + text + ')';
246
248
  return [code, PHP.ORDER_FUNCTION_CALL];
247
249
  };
248
250
 
249
251
  PHP['text_reverse'] = function(block) {
250
- const text = PHP.valueToCode(block, 'TEXT', PHP.ORDER_NONE) || '\'\'';
252
+ const text = PHP.valueToCode(block, 'TEXT', PHP.ORDER_NONE) || "''";
251
253
  const code = 'strrev(' + text + ')';
252
254
  return [code, PHP.ORDER_FUNCTION_CALL];
253
255
  };
@@ -29,13 +29,13 @@ Python['colour_random'] = function(block) {
29
29
 
30
30
  Python['colour_rgb'] = function(block) {
31
31
  // Compose a colour from RGB components expressed as percentages.
32
- const functionName = Python.provideFunction_('colour_rgb', [
33
- 'def ' + Python.FUNCTION_NAME_PLACEHOLDER_ + '(r, g, b):',
34
- ' r = round(min(100, max(0, r)) * 2.55)',
35
- ' g = round(min(100, max(0, g)) * 2.55)',
36
- ' b = round(min(100, max(0, b)) * 2.55)',
37
- ' return \'#%02x%02x%02x\' % (r, g, b)'
38
- ]);
32
+ const functionName = Python.provideFunction_('colour_rgb', `
33
+ def ${Python.FUNCTION_NAME_PLACEHOLDER_}(r, g, b):
34
+ r = round(min(100, max(0, r)) * 2.55)
35
+ g = round(min(100, max(0, g)) * 2.55)
36
+ b = round(min(100, max(0, b)) * 2.55)
37
+ return \'#%02x%02x%02x\' % (r, g, b)
38
+ `);
39
39
  const r = Python.valueToCode(block, 'RED', Python.ORDER_NONE) || 0;
40
40
  const g = Python.valueToCode(block, 'GREEN', Python.ORDER_NONE) || 0;
41
41
  const b = Python.valueToCode(block, 'BLUE', Python.ORDER_NONE) || 0;
@@ -45,17 +45,17 @@ Python['colour_rgb'] = function(block) {
45
45
 
46
46
  Python['colour_blend'] = function(block) {
47
47
  // Blend two colours together.
48
- const functionName = Python.provideFunction_('colour_blend', [
49
- 'def ' + Python.FUNCTION_NAME_PLACEHOLDER_ + '(colour1, colour2, ratio):',
50
- ' r1, r2 = int(colour1[1:3], 16), int(colour2[1:3], 16)',
51
- ' g1, g2 = int(colour1[3:5], 16), int(colour2[3:5], 16)',
52
- ' b1, b2 = int(colour1[5:7], 16), int(colour2[5:7], 16)',
53
- ' ratio = min(1, max(0, ratio))',
54
- ' r = round(r1 * (1 - ratio) + r2 * ratio)',
55
- ' g = round(g1 * (1 - ratio) + g2 * ratio)',
56
- ' b = round(b1 * (1 - ratio) + b2 * ratio)',
57
- ' return \'#%02x%02x%02x\' % (r, g, b)'
58
- ]);
48
+ const functionName = Python.provideFunction_('colour_blend', `
49
+ def ${Python.FUNCTION_NAME_PLACEHOLDER_}(colour1, colour2, ratio):
50
+ r1, r2 = int(colour1[1:3], 16), int(colour2[1:3], 16)
51
+ g1, g2 = int(colour1[3:5], 16), int(colour2[3:5], 16)
52
+ b1, b2 = int(colour1[5:7], 16), int(colour2[5:7], 16)
53
+ ratio = min(1, max(0, ratio))
54
+ r = round(r1 * (1 - ratio) + r2 * ratio)
55
+ g = round(g1 * (1 - ratio) + g2 * ratio)
56
+ b = round(b1 * (1 - ratio) + b2 * ratio)
57
+ return \'#%02x%02x%02x\' % (r, g, b)
58
+ `);
59
59
  const colour1 =
60
60
  Python.valueToCode(block, 'COLOUR1', Python.ORDER_NONE) || '\'#000000\'';
61
61
  const colour2 =
@@ -57,7 +57,7 @@ Python['lists_isEmpty'] = function(block) {
57
57
  Python['lists_indexOf'] = function(block) {
58
58
  // Find an item in the list.
59
59
  const item = Python.valueToCode(block, 'FIND', Python.ORDER_NONE) || '[]';
60
- const list = Python.valueToCode(block, 'VALUE', Python.ORDER_NONE) || '\'\'';
60
+ const list = Python.valueToCode(block, 'VALUE', Python.ORDER_NONE) || "''";
61
61
  let errorIndex = ' -1';
62
62
  let firstIndexAdjustment = '';
63
63
  let lastIndexAdjustment = ' - 1';
@@ -68,21 +68,22 @@ Python['lists_indexOf'] = function(block) {
68
68
  lastIndexAdjustment = '';
69
69
  }
70
70
 
71
+ let functionName;
71
72
  if (block.getFieldValue('END') === 'FIRST') {
72
- const functionName = Python.provideFunction_('first_index', [
73
- 'def ' + Python.FUNCTION_NAME_PLACEHOLDER_ + '(my_list, elem):',
74
- ' try: index = my_list.index(elem)' + firstIndexAdjustment,
75
- ' except: index =' + errorIndex, ' return index'
76
- ]);
77
- const code = functionName + '(' + list + ', ' + item + ')';
78
- return [code, Python.ORDER_FUNCTION_CALL];
73
+ functionName = Python.provideFunction_('first_index', `
74
+ def ${Python.FUNCTION_NAME_PLACEHOLDER_}(my_list, elem):
75
+ try: index = my_list.index(elem)${firstIndexAdjustment}
76
+ except: index =${errorIndex}
77
+ return index
78
+ `);
79
+ } else {
80
+ functionName = Python.provideFunction_('last_index', `
81
+ def ${Python.FUNCTION_NAME_PLACEHOLDER_}(my_list, elem):
82
+ try: index = len(my_list) - my_list[::-1].index(elem)${lastIndexAdjustment}
83
+ except: index =${errorIndex}
84
+ return index
85
+ `);
79
86
  }
80
- const functionName = Python.provideFunction_('last_index', [
81
- 'def ' + Python.FUNCTION_NAME_PLACEHOLDER_ + '(my_list, elem):',
82
- ' try: index = len(my_list) - my_list[::-1].index(elem)' +
83
- lastIndexAdjustment,
84
- ' except: index =' + errorIndex, ' return index'
85
- ]);
86
87
  const code = functionName + '(' + list + ', ' + item + ')';
87
88
  return [code, Python.ORDER_FUNCTION_CALL];
88
89
  };
@@ -152,11 +153,11 @@ Python['lists_getIndex'] = function(block) {
152
153
  return [code, Python.ORDER_FUNCTION_CALL];
153
154
  } else {
154
155
  const functionName =
155
- Python.provideFunction_('lists_remove_random_item', [
156
- 'def ' + Python.FUNCTION_NAME_PLACEHOLDER_ + '(myList):',
157
- ' x = int(random.random() * len(myList))',
158
- ' return myList.pop(x)'
159
- ]);
156
+ Python.provideFunction_('lists_remove_random_item', `
157
+ def ${Python.FUNCTION_NAME_PLACEHOLDER_}(myList):
158
+ x = int(random.random() * len(myList))
159
+ return myList.pop(x)
160
+ `);
160
161
  const code = functionName + '(' + list + ')';
161
162
  if (mode === 'GET_REMOVE') {
162
163
  return [code, Python.ORDER_FUNCTION_CALL];
@@ -294,15 +295,22 @@ Python['lists_sort'] = function(block) {
294
295
  const list = (Python.valueToCode(block, 'LIST', Python.ORDER_NONE) || '[]');
295
296
  const type = block.getFieldValue('TYPE');
296
297
  const reverse = block.getFieldValue('DIRECTION') === '1' ? 'False' : 'True';
297
- const sortFunctionName = Python.provideFunction_('lists_sort', [
298
- 'def ' + Python.FUNCTION_NAME_PLACEHOLDER_ + '(my_list, type, reverse):',
299
- ' def try_float(s):', ' try:', ' return float(s)', ' except:',
300
- ' return 0', ' key_funcs = {', ' "NUMERIC": try_float,',
301
- ' "TEXT": str,', ' "IGNORE_CASE": lambda s: str(s).lower()', ' }',
302
- ' key_func = key_funcs[type]',
303
- ' list_cpy = list(my_list)', // Clone the list.
304
- ' return sorted(list_cpy, key=key_func, reverse=reverse)'
305
- ]);
298
+ const sortFunctionName = Python.provideFunction_('lists_sort', `
299
+ def ${Python.FUNCTION_NAME_PLACEHOLDER_}(my_list, type, reverse):
300
+ def try_float(s):
301
+ try:
302
+ return float(s)
303
+ except:
304
+ return 0
305
+ key_funcs = {
306
+ "NUMERIC": try_float,
307
+ "TEXT": str,
308
+ "IGNORE_CASE": lambda s: str(s).lower()
309
+ }
310
+ key_func = key_funcs[type]
311
+ list_cpy = list(my_list)
312
+ return sorted(list_cpy, key=key_func, reverse=reverse)
313
+ `);
306
314
 
307
315
  const code =
308
316
  sortFunctionName + '(' + list + ', "' + type + '", ' + reverse + ')';
@@ -315,14 +323,14 @@ Python['lists_split'] = function(block) {
315
323
  let code;
316
324
  if (mode === 'SPLIT') {
317
325
  const value_input =
318
- Python.valueToCode(block, 'INPUT', Python.ORDER_MEMBER) || '\'\'';
326
+ Python.valueToCode(block, 'INPUT', Python.ORDER_MEMBER) || "''";
319
327
  const value_delim = Python.valueToCode(block, 'DELIM', Python.ORDER_NONE);
320
328
  code = value_input + '.split(' + value_delim + ')';
321
329
  } else if (mode === 'JOIN') {
322
330
  const value_input =
323
331
  Python.valueToCode(block, 'INPUT', Python.ORDER_NONE) || '[]';
324
332
  const value_delim =
325
- Python.valueToCode(block, 'DELIM', Python.ORDER_MEMBER) || '\'\'';
333
+ Python.valueToCode(block, 'DELIM', Python.ORDER_MEMBER) || "''";
326
334
  code = value_delim + '.join(' + value_input + ')';
327
335
  } else {
328
336
  throw Error('Unknown mode: ' + mode);
@@ -70,16 +70,20 @@ Python['controls_for'] = function(block) {
70
70
 
71
71
  // Helper functions.
72
72
  const defineUpRange = function() {
73
- return Python.provideFunction_('upRange', [
74
- 'def ' + Python.FUNCTION_NAME_PLACEHOLDER_ + '(start, stop, step):',
75
- ' while start <= stop:', ' yield start', ' start += abs(step)'
76
- ]);
73
+ return Python.provideFunction_('upRange', `
74
+ def ${Python.FUNCTION_NAME_PLACEHOLDER_}(start, stop, step):
75
+ while start <= stop:
76
+ yield start
77
+ start += abs(step)
78
+ `);
77
79
  };
78
80
  const defineDownRange = function() {
79
- return Python.provideFunction_('downRange', [
80
- 'def ' + Python.FUNCTION_NAME_PLACEHOLDER_ + '(start, stop, step):',
81
- ' while start >= stop:', ' yield start', ' start -= abs(step)'
82
- ]);
81
+ return Python.provideFunction_('downRange', `
82
+ def ${Python.FUNCTION_NAME_PLACEHOLDER_}(start, stop, step):
83
+ while start >= stop:
84
+ yield start
85
+ start -= abs(step)
86
+ `);
83
87
  };
84
88
  // Arguments are legal Python code (numbers or strings returned by scrub()).
85
89
  const generateUpDownRange = function(start, end, inc) {