utility.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. /**
  2. * @license
  3. * Visual Blocks Editor
  4. *
  5. * Copyright 2012 Google Inc.
  6. * https://developers.google.com/blockly/
  7. *
  8. * Licensed under the Apache License, Version 2.0 (the "License");
  9. * you may not use this file except in compliance with the License.
  10. * You may obtain a copy of the License at
  11. *
  12. * http://www.apache.org/licenses/LICENSE-2.0
  13. *
  14. * Unless required by applicable law or agreed to in writing, software
  15. * distributed under the License is distributed on an "AS IS" BASIS,
  16. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17. * See the License for the specific language governing permissions and
  18. * limitations under the License.
  19. */
  20. /**
  21. * @fileoverview Utility blocks for Blockly.
  22. * @author acbart@vt.edu (Austin Cory Bart)
  23. */
  24. 'use strict';
  25. goog.provide('Blockly.Blocks.utility');
  26. goog.require('Blockly.Blocks');
  27. Blockly.Blocks.utility.HUE = 160;
  28. Blockly.Blocks['raw_table'] = {
  29. // Container.
  30. init: function() {
  31. this.setColour(Blockly.Blocks.utility.HUE);
  32. this.setPreviousStatement(true);
  33. this.setNextStatement(true);
  34. this.appendDummyInput()
  35. .appendField('Tabular Abstraction:');
  36. this.appendDummyInput()
  37. .appendField(new Blockly.FieldTable(''), 'TEXT');
  38. }
  39. };
  40. Blockly.Blocks['raw_block'] = {
  41. // Container.
  42. init: function() {
  43. this.setColour(Blockly.Blocks.utility.HUE);
  44. this.setPreviousStatement(true);
  45. this.setNextStatement(true);
  46. this.appendDummyInput()
  47. .appendField('Code Block:');
  48. this.appendDummyInput()
  49. .appendField(new Blockly.FieldTextArea(''), 'TEXT');
  50. }
  51. };
  52. Blockly.Blocks['raw_expression'] = {
  53. // Container.
  54. init: function() {
  55. this.setColour(Blockly.Blocks.utility.HUE);
  56. this.appendDummyInput()
  57. .appendField('Code Expression:');
  58. this.appendDummyInput()
  59. .appendField(new Blockly.FieldTextArea(''), 'TEXT');
  60. this.setOutput(true);
  61. }
  62. };
  63. Blockly.Blocks['raw_empty'] = {
  64. // Container.
  65. init: function() {
  66. this.setColour(Blockly.Blocks.utility.HUE);
  67. this.setPreviousStatement(true);
  68. this.setNextStatement(true);
  69. this.appendValueInput('VALUE')
  70. .appendField('');
  71. this.setInputsInline(false);
  72. }
  73. };
  74. Blockly.Blocks['text_comment'] = {
  75. // Text value.
  76. init: function() {
  77. this.setColour(Blockly.Blocks.utility.HUE);
  78. this.appendDummyInput()
  79. .appendTitle('Comment:')
  80. .appendTitle(new Blockly.FieldTextInput(''), 'TEXT');
  81. this.setPreviousStatement(true);
  82. this.setNextStatement(true);
  83. this.setTooltip('This comment will be ignored by Python');
  84. }
  85. };
  86. Blockly.Blocks['type_check'] = {
  87. // Set element at index.
  88. init: function() {
  89. this.setColour(Blockly.Blocks.utility.HUE);
  90. this.appendValueInput('VALUE')
  91. .appendField(Blockly.Msg.TYPE_CHECK);
  92. this.setInputsInline(false);
  93. this.setOutput(true, 'Type');
  94. //this.setPreviousStatement(true);
  95. //this.setNextStatement(true);
  96. }
  97. };
  98. Blockly.Blocks['text_print_multiple'] = {
  99. /**
  100. * Block for printing multiple things (including nothing)
  101. * @this Blockly.Block
  102. */
  103. init: function() {
  104. this.setColour(Blockly.Blocks.utility.HUE);
  105. this.itemCount_ = 1;
  106. this.updateShape_();
  107. this.setPreviousStatement(true);
  108. this.setNextStatement(true);
  109. this.setMutator(new Blockly.Mutator(['text_print_multiple_item']));
  110. this.setTooltip(Blockly.Msg.TEXT_PRINT_TOOLTIP);
  111. },
  112. /**
  113. * Create XML to represent print inputs.
  114. * @return {Element} XML storage element.
  115. * @this Blockly.Block
  116. */
  117. mutationToDom: function(workspace) {
  118. var container = document.createElement('mutation');
  119. container.setAttribute('items', this.itemCount_);
  120. return container;
  121. },
  122. /**
  123. * Parse XML to restore the list inputs.
  124. * @param {!Element} xmlElement XML storage element.
  125. * @this Blockly.Block
  126. */
  127. domToMutation: function(xmlElement) {
  128. this.itemCount_ = parseInt(xmlElement.getAttribute('items'), 10);
  129. this.updateShape_();
  130. },
  131. /**
  132. * Populate the mutator's dialog with this block's components.
  133. * @param {!Blockly.Workspace} workspace Mutator's workspace.
  134. * @return {!Blockly.Block} Root block in mutator.
  135. * @this Blockly.Block
  136. */
  137. decompose: function(workspace) {
  138. var containerBlock = Blockly.Block.obtain(workspace,
  139. 'text_print_multiple_container');
  140. containerBlock.initSvg();
  141. var connection = containerBlock.getInput('STACK').connection;
  142. for (var x = 0; x < this.itemCount_; x++) {
  143. var itemBlock = Blockly.Block.obtain(workspace, 'text_print_multiple_item');
  144. itemBlock.initSvg();
  145. connection.connect(itemBlock.previousConnection);
  146. connection = itemBlock.nextConnection;
  147. }
  148. return containerBlock;
  149. },
  150. /**
  151. * Reconfigure this block based on the mutator dialog's components.
  152. * @param {!Blockly.Block} containerBlock Root block in mutator.
  153. * @this Blockly.Block
  154. */
  155. compose: function(containerBlock) {
  156. var itemBlock = containerBlock.getInputTargetBlock('STACK');
  157. // Count number of inputs.
  158. var connections = [];
  159. var i = 0;
  160. while (itemBlock) {
  161. connections[i] = itemBlock.valueConnection_;
  162. itemBlock = itemBlock.nextConnection &&
  163. itemBlock.nextConnection.targetBlock();
  164. i++;
  165. }
  166. this.itemCount_ = i;
  167. this.updateShape_();
  168. // Reconnect any child blocks.
  169. for (var i = 0; i < this.itemCount_; i++) {
  170. if (connections[i]) {
  171. this.getInput('PRINT' + i).connection.connect(connections[i]);
  172. }
  173. }
  174. },
  175. /**
  176. * Store pointers to any connected child blocks.
  177. * @param {!Blockly.Block} containerBlock Root block in mutator.
  178. * @this Blockly.Block
  179. */
  180. saveConnections: function(containerBlock) {
  181. // Store a pointer to any connected child blocks.
  182. var itemBlock = containerBlock.getInputTargetBlock('STACK');
  183. var x = 0;
  184. while (itemBlock) {
  185. var input = this.getInput('PRINT' + x);
  186. itemBlock.valueConnection_ = input && input.connection.targetConnection;
  187. x++;
  188. itemBlock = itemBlock.nextConnection &&
  189. itemBlock.nextConnection.targetBlock();
  190. }
  191. },
  192. /**
  193. * Modify this block to have the correct number of inputs.
  194. * @private
  195. * @this Blockly.Block
  196. */
  197. updateShape_: function() {
  198. // Delete everything.
  199. if (this.getInput('EMPTY')) {
  200. this.removeInput('EMPTY');
  201. } else {
  202. var i = 0;
  203. while (this.getInput('PRINT' + i)) {
  204. this.removeInput('PRINT' + i);
  205. i++;
  206. }
  207. }
  208. // Rebuild block.
  209. if (this.itemCount_ == 0) {
  210. this.appendDummyInput('EMPTY')
  211. .appendField("print");
  212. } else {
  213. for (var i = 0; i < this.itemCount_; i++) {
  214. var input = this.appendValueInput('PRINT' + i);
  215. if (i == 0) {
  216. input.appendField("print");
  217. }
  218. }
  219. }
  220. }
  221. };
  222. Blockly.Blocks['text_print_multiple_container'] = {
  223. // Container.
  224. init: function() {
  225. this.setColour(Blockly.Blocks.utility.HUE);
  226. this.appendDummyInput()
  227. .appendField('print');
  228. this.appendStatementInput('STACK');
  229. this.setTooltip('');
  230. this.contextMenu = false;
  231. }
  232. };
  233. Blockly.Blocks['text_print_multiple_item'] = {
  234. // Add items.
  235. init: function() {
  236. this.setColour(Blockly.Blocks.utility.HUE);
  237. this.appendDummyInput()
  238. .appendField('item');
  239. this.setInputsInline(true);
  240. this.setPreviousStatement(true);
  241. this.setNextStatement(true);
  242. this.setTooltip('');
  243. this.contextMenu = false;
  244. }
  245. };
  246. Blockly.Blocks['function_call'] = {
  247. /**
  248. * Block for printing multiple things (including nothing)
  249. * @this Blockly.Block
  250. */
  251. init: function() {
  252. this.setColour(Blockly.Blocks.utility.HUE);
  253. this.itemCount_ = 1;
  254. this.hasReturn_ = false;
  255. this.appendDummyInput()
  256. .appendField(new Blockly.FieldTextInput("str"), 'NAME');
  257. this.updateShape_();
  258. this.setMutator(new Blockly.Mutator(['function_call_item']));
  259. this.setTooltip("Can be used to call any function");
  260. },
  261. /**
  262. * Create XML to represent print inputs.
  263. * @return {Element} XML storage element.
  264. * @this Blockly.Block
  265. */
  266. mutationToDom: function(workspace) {
  267. var container = document.createElement('mutation');
  268. container.setAttribute('items', this.itemCount_);
  269. container.setAttribute('hasReturn', this.hasReturn_ ? "TRUE": "FALSE");
  270. return container;
  271. },
  272. /**
  273. * Parse XML to restore the list inputs.
  274. * @param {!Element} xmlElement XML storage element.
  275. * @this Blockly.Block
  276. */
  277. domToMutation: function(xmlElement) {
  278. this.itemCount_ = parseInt(xmlElement.getAttribute('items'), 10);
  279. this.hasReturn_ = xmlElement.getAttribute('hasReturn') === "TRUE";
  280. this.updateShape_();
  281. },
  282. /**
  283. * Populate the mutator's dialog with this block's components.
  284. * @param {!Blockly.Workspace} workspace Mutator's workspace.
  285. * @return {!Blockly.Block} Root block in mutator.
  286. * @this Blockly.Block
  287. */
  288. decompose: function(workspace) {
  289. var containerBlock = Blockly.Block.obtain(workspace,
  290. 'function_call_container');
  291. containerBlock.initSvg();
  292. containerBlock.setFieldValue(this.hasStatements_ ? 'TRUE' : 'FALSE',
  293. 'RETURN');
  294. var connection = containerBlock.getInput('STACK').connection;
  295. for (var x = 0; x < this.itemCount_; x++) {
  296. var itemBlock = Blockly.Block.obtain(workspace, 'function_call_item');
  297. itemBlock.initSvg();
  298. connection.connect(itemBlock.previousConnection);
  299. connection = itemBlock.nextConnection;
  300. }
  301. return containerBlock;
  302. },
  303. /**
  304. * Notification that the procedure's return state has changed.
  305. * @param {boolean} returnState New return state
  306. * @this Blockly.Block
  307. */
  308. setReturn: function(returnState) {
  309. this.unplug(true, true);
  310. this.setOutput(returnState);
  311. this.setPreviousStatement(!returnState);
  312. this.setNextStatement(!returnState);
  313. if (this.rendered) {
  314. this.render();
  315. }
  316. },
  317. /**
  318. * Reconfigure this block based on the mutator dialog's components.
  319. * @param {!Blockly.Block} containerBlock Root block in mutator.
  320. * @this Blockly.Block
  321. */
  322. compose: function(containerBlock) {
  323. var itemBlock = containerBlock.getInputTargetBlock('STACK');
  324. // Count number of inputs.
  325. var connections = [];
  326. var i = 0;
  327. while (itemBlock) {
  328. connections[i] = itemBlock.valueConnection_;
  329. itemBlock = itemBlock.nextConnection &&
  330. itemBlock.nextConnection.targetBlock();
  331. i++;
  332. }
  333. this.itemCount_ = i;
  334. this.hasReturn_ = containerBlock.getFieldValue("RETURN") === "TRUE";
  335. this.updateShape_();
  336. // Reconnect any child blocks.
  337. for (var i = 0; i < this.itemCount_; i++) {
  338. if (connections[i]) {
  339. this.getInput('ARGUMENT' + i).connection.connect(connections[i]);
  340. }
  341. }
  342. },
  343. /**
  344. * Store pointers to any connected child blocks.
  345. * @param {!Blockly.Block} containerBlock Root block in mutator.
  346. * @this Blockly.Block
  347. */
  348. saveConnections: function(containerBlock) {
  349. // Store a pointer to any connected child blocks.
  350. var itemBlock = containerBlock.getInputTargetBlock('STACK');
  351. var x = 0;
  352. while (itemBlock) {
  353. var input = this.getInput('ARGUMENT' + x);
  354. itemBlock.valueConnection_ = input && input.connection.targetConnection;
  355. x++;
  356. itemBlock = itemBlock.nextConnection &&
  357. itemBlock.nextConnection.targetBlock();
  358. }
  359. },
  360. /**
  361. * Modify this block to have the correct number of inputs.
  362. * @private
  363. * @this Blockly.Block
  364. */
  365. updateShape_: function() {
  366. // Delete everything.
  367. if (this.getInput('EMPTY')) {
  368. this.removeInput('EMPTY');
  369. } else {
  370. var i = 0;
  371. while (this.getInput('ARGUMENT' + i)) {
  372. this.removeInput('ARGUMENT' + i);
  373. i++;
  374. }
  375. }
  376. // Rebuild block.
  377. for (var i = 0; i < this.itemCount_; i++) {
  378. var input = this.appendValueInput('ARGUMENT' + i);
  379. }
  380. // Set whether returns anything
  381. this.setReturn(this.hasReturn_);
  382. }
  383. };
  384. Blockly.Blocks['function_call_container'] = {
  385. // Container.
  386. init: function() {
  387. this.setColour(Blockly.Blocks.utility.HUE);
  388. this.appendDummyInput()
  389. .appendField('Arguments');
  390. this.appendStatementInput('STACK');
  391. this.appendDummyInput()
  392. .setAlign(Blockly.ALIGN_RIGHT)
  393. .appendField('has return')
  394. .appendField(new Blockly.FieldCheckbox('TRUE'),
  395. 'RETURN');
  396. this.setTooltip('');
  397. this.contextMenu = false;
  398. }
  399. };
  400. Blockly.Blocks['function_call_item'] = {
  401. // Add items.
  402. init: function() {
  403. this.setColour(Blockly.Blocks.utility.HUE);
  404. this.appendDummyInput()
  405. .appendField('argument');
  406. this.setInputsInline(true);
  407. this.setPreviousStatement(true);
  408. this.setNextStatement(true);
  409. this.setTooltip('');
  410. this.contextMenu = false;
  411. }
  412. };