block_exporter_controller.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. /**
  2. * @license
  3. * Blockly Demos: Block Factory
  4. *
  5. * Copyright 2016 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 Javascript for the Block Exporter Controller class. Allows
  22. * users to export block definitions and generator stubs of their saved blocks
  23. * easily using a visual interface. Depends on Block Exporter View and Block
  24. * Exporter Tools classes. Interacts with Export Settings in the index.html.
  25. *
  26. * @author quachtina96 (Tina Quach)
  27. */
  28. 'use strict';
  29. goog.provide('BlockExporterController');
  30. goog.require('FactoryUtils');
  31. goog.require('StandardCategories');
  32. goog.require('BlockExporterView');
  33. goog.require('BlockExporterTools');
  34. goog.require('goog.dom.xml');
  35. /**
  36. * BlockExporter Controller Class
  37. * @param {!BlockLibrary.Storage} blockLibStorage Block Library Storage.
  38. * @constructor
  39. */
  40. BlockExporterController = function(blockLibStorage) {
  41. // BlockLibrary.Storage object containing user's saved blocks.
  42. this.blockLibStorage = blockLibStorage;
  43. // Utils for generating code to export.
  44. this.tools = new BlockExporterTools();
  45. // The ID of the block selector, a div element that will be populated with the
  46. // block options.
  47. this.selectorID = 'blockSelector';
  48. // Map of block types stored in block library to their corresponding Block
  49. // Option objects.
  50. this.blockOptions = this.tools.createBlockSelectorFromLib(
  51. this.blockLibStorage, this.selectorID);
  52. // View provides the block selector and export settings UI.
  53. this.view = new BlockExporterView(this.blockOptions);
  54. };
  55. /**
  56. * Set the block library storage object from which exporter exports.
  57. * @param {!BlockLibraryStorage} blockLibStorage Block Library Storage object
  58. * that stores the blocks.
  59. */
  60. BlockExporterController.prototype.setBlockLibraryStorage =
  61. function(blockLibStorage) {
  62. this.blockLibStorage = blockLibStorage;
  63. };
  64. /**
  65. * Get the block library storage object from which exporter exports.
  66. * @return {!BlockLibraryStorage} blockLibStorage Block Library Storage object
  67. * that stores the blocks.
  68. */
  69. BlockExporterController.prototype.getBlockLibraryStorage =
  70. function(blockLibStorage) {
  71. return this.blockLibStorage;
  72. };
  73. /**
  74. * Get selected blocks from block selector, pulls info from the Export
  75. * Settings form in Block Exporter, and downloads code accordingly.
  76. */
  77. BlockExporterController.prototype.export = function() {
  78. // Get selected blocks' information.
  79. var blockTypes = this.view.getSelectedBlockTypes();
  80. var blockXmlMap = this.blockLibStorage.getBlockXmlMap(blockTypes);
  81. // Pull block definition(s) settings from the Export Settings form.
  82. var wantBlockDef = document.getElementById('blockDefCheck').checked;
  83. var definitionFormat = document.getElementById('exportFormat').value;
  84. var blockDef_filename = document.getElementById('blockDef_filename').value;
  85. // Pull block generator stub(s) settings from the Export Settings form.
  86. var wantGenStub = document.getElementById('genStubCheck').checked;
  87. var language = document.getElementById('exportLanguage').value;
  88. var generatorStub_filename = document.getElementById(
  89. 'generatorStub_filename').value;
  90. if (wantBlockDef) {
  91. // User wants to export selected blocks' definitions.
  92. if (!blockDef_filename) {
  93. // User needs to enter filename.
  94. alert('Please enter a filename for your block definition(s) download.');
  95. } else {
  96. // Get block definition code in the selected format for the blocks.
  97. var blockDefs = this.tools.getBlockDefinitions(blockXmlMap,
  98. definitionFormat);
  99. // Download the file, using .js file ending for JSON or Javascript.
  100. FactoryUtils.createAndDownloadFile(
  101. blockDefs, blockDef_filename, 'javascript');
  102. }
  103. }
  104. if (wantGenStub) {
  105. // User wants to export selected blocks' generator stubs.
  106. if (!generatorStub_filename) {
  107. // User needs to enter filename.
  108. alert('Please enter a filename for your generator stub(s) download.');
  109. } else {
  110. // Get generator stub code in the selected language for the blocks.
  111. var genStubs = this.tools.getGeneratorCode(blockXmlMap,
  112. language);
  113. // Get the correct file extension.
  114. var fileType = (language == 'JavaScript') ? 'javascript' : 'plain';
  115. // Download the file.
  116. FactoryUtils.createAndDownloadFile(
  117. genStubs, generatorStub_filename, fileType);
  118. }
  119. }
  120. };
  121. /**
  122. * Update the Exporter's block selector with block options generated from blocks
  123. * stored in block library.
  124. */
  125. BlockExporterController.prototype.updateSelector = function() {
  126. // Get previously selected block types.
  127. var oldSelectedTypes = this.view.getSelectedBlockTypes();
  128. // Generate options from block library and assign to view.
  129. this.blockOptions = this.tools.createBlockSelectorFromLib(
  130. this.blockLibStorage, this.selectorID);
  131. this.addBlockOptionSelectHandlers();
  132. this.view.setBlockOptions(this.blockOptions);
  133. // Select all previously selected blocks.
  134. for (var i = 0, blockType; blockType = oldSelectedTypes[i]; i++) {
  135. if (this.blockOptions[blockType]) {
  136. this.view.select(blockType);
  137. }
  138. }
  139. this.view.listSelectedBlocks();
  140. };
  141. /**
  142. * Tied to the 'Clear Selected Blocks' button in the Block Exporter.
  143. * Deselects all blocks in the selector and updates text accordingly.
  144. */
  145. BlockExporterController.prototype.clearSelectedBlocks = function() {
  146. this.view.deselectAllBlocks();
  147. this.view.listSelectedBlocks();
  148. };
  149. /**
  150. * Tied to the 'All Stored' button in the Block Exporter 'Select' dropdown.
  151. * Selects all blocks stored in block library for export.
  152. */
  153. BlockExporterController.prototype.selectAllBlocks = function() {
  154. var allBlockTypes = this.blockLibStorage.getBlockTypes();
  155. for (var i = 0, blockType; blockType = allBlockTypes[i]; i++) {
  156. this.view.select(blockType);
  157. }
  158. this.view.listSelectedBlocks();
  159. };
  160. /**
  161. * Returns the category XML containing all blocks in the block library.
  162. * @return {Element} XML for a category to be used in toolbox.
  163. */
  164. BlockExporterController.prototype.getBlockLibraryCategory = function() {
  165. return this.tools.generateCategoryFromBlockLib(this.blockLibStorage);
  166. };
  167. /**
  168. * Add select handlers to each block option to update the view and the selected
  169. * blocks accordingly.
  170. */
  171. BlockExporterController.prototype.addBlockOptionSelectHandlers = function() {
  172. var self = this;
  173. // Click handler for a block option. Toggles whether or not it's selected and
  174. // updates helper text accordingly.
  175. var updateSelectedBlockTypes_ = function(blockOption) {
  176. // Toggle selected.
  177. blockOption.setSelected(!blockOption.isSelected());
  178. // Show currently selected blocks in helper text.
  179. self.view.listSelectedBlocks();
  180. };
  181. // Returns a block option select handler.
  182. var makeBlockOptionSelectHandler_ = function(blockOption) {
  183. return function() {
  184. updateSelectedBlockTypes_(blockOption);
  185. self.updatePreview();
  186. };
  187. };
  188. // Assign a click handler to each block option.
  189. for (var blockType in this.blockOptions) {
  190. var blockOption = this.blockOptions[blockType];
  191. // Use an additional closure to correctly assign the tab callback.
  192. blockOption.dom.addEventListener(
  193. 'click', makeBlockOptionSelectHandler_(blockOption));
  194. }
  195. };
  196. /**
  197. * Tied to the 'All Used' button in the Block Exporter's 'Select' button.
  198. * Selects all blocks stored in block library and used in workspace factory.
  199. */
  200. BlockExporterController.prototype.selectUsedBlocks = function() {
  201. // Deselect all blocks.
  202. this.view.deselectAllBlocks();
  203. // Get list of block types that are in block library and used in workspace
  204. // factory.
  205. var storedBlockTypes = this.blockLibStorage.getBlockTypes();
  206. var sharedBlockTypes = [];
  207. // Keep list of custom block types used but not in library.
  208. var unstoredCustomBlockTypes = [];
  209. for (var i = 0, blockType; blockType = this.usedBlockTypes[i]; i++) {
  210. if (storedBlockTypes.indexOf(blockType) != -1) {
  211. sharedBlockTypes.push(blockType);
  212. } else if (StandardCategories.coreBlockTypes.indexOf(blockType) == -1) {
  213. unstoredCustomBlockTypes.push(blockType);
  214. }
  215. }
  216. // Select each shared block type.
  217. for (var i = 0, blockType; blockType = sharedBlockTypes[i]; i++) {
  218. this.view.select(blockType);
  219. }
  220. this.view.listSelectedBlocks();
  221. if (unstoredCustomBlockTypes.length > 0){
  222. // Warn user to import block defifnitions and generator code for blocks
  223. // not in their Block Library nor Blockly's standard library.
  224. var blockTypesText = unstoredCustomBlockTypes.join(', ');
  225. var customWarning = 'Custom blocks used in workspace factory but not ' +
  226. 'stored in block library:\n ' + blockTypesText +
  227. '\n\nDon\'t forget to include block definitions and generator code ' +
  228. 'for these blocks.';
  229. alert(customWarning);
  230. }
  231. };
  232. /**
  233. * Set the array that holds the block types used in workspace factory.
  234. * @param {!Array.<string>} usedBlockTypes Block types used in
  235. */
  236. BlockExporterController.prototype.setUsedBlockTypes =
  237. function(usedBlockTypes) {
  238. this.usedBlockTypes = usedBlockTypes;
  239. };
  240. /**
  241. * Updates preview code (block definitions and generator stubs) in the exporter
  242. * preview to reflect selected blocks.
  243. */
  244. BlockExporterController.prototype.updatePreview = function() {
  245. // Generate preview code for selected blocks.
  246. var blockDefs = this.getBlockDefinitionsOfSelected();
  247. var genStubs = this.getGeneratorStubsOfSelected();
  248. // Update the text areas containing the code.
  249. FactoryUtils.injectCode(blockDefs, 'blockDefs_textArea');
  250. FactoryUtils.injectCode(genStubs, 'genStubs_textArea');
  251. };
  252. /**
  253. * Returns a map of each selected block's type to its corresponding XML.
  254. * @return {!Object} A map of each selected block's type (a string) to its
  255. * corresponding XML element.
  256. */
  257. BlockExporterController.prototype.getSelectedBlockXmlMap = function() {
  258. var blockTypes = this.view.getSelectedBlockTypes();
  259. return this.blockLibStorage.getBlockXmlMap(blockTypes);
  260. };
  261. /**
  262. * Get block definition code in the selected format for selected blocks.
  263. * @return {string} The concatenation of each selected block's language code
  264. * in the format specified in export settings.
  265. */
  266. BlockExporterController.prototype.getBlockDefinitionsOfSelected = function() {
  267. // Get selected blocks' information.
  268. var blockXmlMap = this.getSelectedBlockXmlMap();
  269. // Get block definition code in the selected format for the blocks.
  270. var definitionFormat = document.getElementById('exportFormat').value;
  271. return this.tools.getBlockDefinitions(blockXmlMap, definitionFormat);
  272. };
  273. /**
  274. * Get generator stubs in the selected language for selected blocks.
  275. * @return {string} The concatenation of each selected block's generator stub
  276. * in the language specified in export settings.
  277. */
  278. BlockExporterController.prototype.getGeneratorStubsOfSelected = function() {
  279. // Get selected blocks' information.
  280. var blockXmlMap = this.getSelectedBlockXmlMap();
  281. // Get generator stub code in the selected language for the blocks.
  282. var language = document.getElementById('exportLanguage').value;
  283. return this.tools.getGeneratorCode(blockXmlMap, language);
  284. };