See More

/** * An object that manages the various editors, where users can edit their program. Also manages the * movement between editors. * There are currently two editors: * - Blocks: A Blockly instance * - Text: A html textbox * * @constructor * @this {BlockPyEditor} */ function BlockPyEditor() { // This tool is what actually converts text to blocks! this.converter = new PythonToBlocks(); // HTML DOM accessors this.blocklyDiv = document.querySelectorAll('.blockly-div'); // Blockly and CodeMirror instances this.blockly = null; // The updateStack keeps track of whether an update is percolating, to prevent duplicate update events. this.silenceBlock = false; this.silenceBlockTimer = null; this.silenceText = false; this.oldCode = ""; //DA ELIMINARE // Hack to prevent chrome errors. Forces audio to load on demand. // See: https://github.com/google/blockly/issues/299 //NON HO CAPITO BENE A COSA SERVE. FORSE PERMETTE DI RISOLVERE UN BUG IN CHROMIUM Blockly.WorkspaceSvg.prototype.preloadAudio_ = function() {}; // Initialize subcomponents this.initText(); this.initBlockly(); //SERVONO SOLO INIZIALMENTE this.updateBlocksFromModel(); this.updateTextFromModel(); } /** * Initializes the Blockly instance (handles all the blocks). This includes * attaching a number of ChangeListeners that can keep the internal code * representation updated and enforce type checking. */ BlockPyEditor.prototype.initBlockly = function() { //alert("initBlockly"); this.blockly = Blockly.inject(this.blocklyDiv[0], { path: "blockly/", scrollbars: true, zoom: {enabled: false}, oneBasedIndex: false, comments: false, toolbox: this.updateToolbox(false)}); // Register model changer var editor = this; this.blockly.addChangeListener(function(evt) { //alert("eventListener"); editor.updateBlocks(); }); // Force the proper window size this.blockly.resize(); }; /** * Initializes the CodeMirror instance. This handles text editing (with syntax highlighting) * and also attaches a listener for change events to update the internal code represntation. */ BlockPyEditor.prototype.initText = function() { //alert("initText"); // Register model changer var editor = this; $('.codemirror-div').keyup(function() { //alert("change"); editor.updateText(); }); }; /** * Actually changes the value of the CodeMirror instance * * @param {String} code - The new code for the CodeMirror */ BlockPyEditor.prototype.setText = function(code) { //alert("setText"); if (code == undefined || code.trim() == "") { $('.codemirror-div').val("\n"); } else { $('.codemirror-div').val(code); } } BlockPyEditor.prototype.setBlocks = function(python_code) { //alert("setBlocks"); var xml_code = ""; if (python_code !== '' && python_code !== undefined && python_code.trim().charAt(0) !== '<') { var result = this.converter.convertSource(python_code); xml_code = result.xml; } var error_code = this.converter.convertSourceToCodeBlock(python_code); var errorXml = Blockly.Xml.textToDom(error_code); if (python_code == '' || python_code == undefined || python_code.trim() == '') { this.blockly.clear(); } else if (xml_code !== '' && xml_code !== undefined) { var blocklyXml = Blockly.Xml.textToDom(xml_code); try { this.setBlocksFromXml(blocklyXml); } catch (e) { console.error(e); this.setBlocksFromXml(errorXml); } } else { this.setBlocksFromXml(errorXml); } Blockly.Events.disable(); this.blockly.align(); Blockly.Events.enable(); } BlockPyEditor.prototype.clearDeadBlocks = function() { //alert("clearDeadBlocks"); var all_blocks = this.blockly.getAllBlocks(); all_blocks.forEach(function(elem) { if (!Blockly.Python[elem.type]) { elem.dispose(true); } }); } /** * Attempts to update the model for the current code file from the * block workspace. Might be prevented if an update event was already * percolating. */ BlockPyEditor.prototype.updateBlocks = function() { //alert("updateBlocks"); if (! this.silenceBlock) { try { var newCode = Blockly.Python.workspaceToCode(this.blockly); } catch (e) { this.clearDeadBlocks(); } this.silenceText = true; this.setText(newCode); } } /** * Attempts to update the model for the current code file from the * text editor. Might be prevented if an update event was already * percolating. Also unhighlights any lines. */ var timerGuard = null; BlockPyEditor.prototype.updateText = function() { //alert("updateText"); if (! this.silenceText) { var newCode = $('.codemirror-div').val(); // Update Blocks this.silenceBlock = true; this.setBlocks(newCode); this.resetBlockSilence(); //this.silenceBlock = false; } this.silenceText = false; } /** * Resets the silenceBlock after a short delay */ BlockPyEditor.prototype.resetBlockSilence = function() { //alert("resetBlockSilence"); var editor = this; if (editor.silenceBlockTimer != null) { clearTimeout(editor.silenceBlockTimer); } this.silenceBlockTimer = window.setTimeout(function() { editor.silenceBlock = false; editor.silenceBlockTimer = null; }, 40); }; /** * Updates the text editor from the current code file in the * model. Might be prevented if an update event was already * percolating. */ BlockPyEditor.prototype.updateTextFromModel = function() { //alert("updateTextFromModel"); var code = Blockly.Python.workspaceToCode(this.blockly); this.setText(code); } /** * Updates the block editor from the current code file in the * model. Might be prevented if an update event was already * percolating. This can also report an error if one occurs. * * @returns {Boolean} Returns true upon success. */ BlockPyEditor.prototype.updateBlocksFromModel = function() { var code = "print('ciao')"; this.silenceBlock = true; this.setBlocks(code); this.resetBlockSilence(); //this.silenceBlock = false; } /** * Helper function for retrieving the current Blockly workspace as * an XML DOM object. * * @returns {XMLDom} The blocks in the current workspace. */ BlockPyEditor.prototype.getBlocksFromXml = function() { //alert("getBlocksFromXml"); return Blockly.Xml.workspaceToDom(this.blockly); } /** * Helper function for setting the current Blockly workspace to * whatever XML DOM is given. This clears out any existing blocks. */ BlockPyEditor.prototype.setBlocksFromXml = function(xml) { //alert("setBlocksFromXml"); Blockly.Xml.domToWorkspaceDestructive(xml, this.blockly); } /** * Maps short category names in the toolbox to the full XML used to * represent that category as usual. This is kind of a clunky mechanism * for managing the different categories, and doesn't allow us to specify * individual blocks. */ BlockPyEditor.CATEGORY_MAP = { 'Variables': ''+ '', 'Decisions': ''+ ''+ ''+ ''+ ''+ ''+ '', 'Iteration': ''+ ''+ '', 'Functions': ''+ '', 'Classes': ''+ ''+ ''+ ''+ ''+ '', 'Calculation': ''+ ''+ ''+ '', 'Python': ''+ ''+ ''+ '', 'Output': ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ '', 'Turtles': ''+ ''+ ''+ ''+ ''+ ''+ ''+ '', 'Values': ''+ ''+ ''+ ''+ '', 'Tuples': ''+ ''+ '', 'Lists': ''+ ''+ ''+ '0'+ ''+ ''+ '0'+ ''+ ''+ '0'+ ''+ ''+ ''+ ''+ ''+ '', 'Dictionaries': ''+ ''+ ''+ '', 'Data - Parking': ''+ ''+ ''+ ''+ 'EQ'+ ''+ ''+ ''+ '1'+ '00'+ 'PM'+ ''+ ''+ ''+ ''+ 'EQ'+ ''+ ''+ 'Monday'+ ''+ ''+ ''+ '', 'My Block' : ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ '', 'Separator': '' }; /** * Creates an updated representation of the Toolboxes XML as currently specified in the * model, using whatever modules have been added or removed. This method can either set it * or just retrieve it for future use. * * @param {Boolean} only_set - Whether to return the XML string or to actually set the XML. False means that it will not update the toolbox! * @returns {String?} Possibly returns the XML of the toolbox as a string. */ BlockPyEditor.prototype.updateToolbox = function(only_set) { //alert("updateToolbox"); var xml = ''; if (only_set) { this.blockly.updateToolbox(xml); this.blockly.resize(); } else { return xml; } };