From acb9effd5205b6f2538ecf04bc82f9d55d41ba68 Mon Sep 17 00:00:00 2001 From: Silver Kuusik Date: Sun, 8 Jul 2018 20:52:16 +0200 Subject: [PATCH] Create blockly.js --- assets/js/blockly.js | 250 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 assets/js/blockly.js diff --git a/assets/js/blockly.js b/assets/js/blockly.js new file mode 100644 index 0000000..4f93d4c --- /dev/null +++ b/assets/js/blockly.js @@ -0,0 +1,250 @@ +window.addEventListener("load", function() { + // To remember the control_if blockId + var controlBlockId = ""; + + // Change the if block to be more cheerful + Blockly.Msg.LOGIC_HUE = '#44CC00'; + + // Remote previous and next statement from control_if block + Blockly.defineBlocksWithJsonArray([ + { + "type": "controls_if", + "message0": "%{BKY_CONTROLS_IF_MSG_IF} %1", + "args0": [ + { + "type": "input_value", + "name": "IF0", + "check": "Boolean" + } + ], + "message1": "%{BKY_CONTROLS_IF_MSG_THEN} %1", + "args1": [ + { + "type": "input_statement", + "name": "DO0" + } + ], + "colour": "%{BKY_LOGIC_HUE}", + "helpUrl": "%{BKY_CONTROLS_IF_HELPURL}", + "mutator": "controls_if_mutator", + "extensions": ["controls_if_tooltip"] + } + ]); + + // Make control_if mutator icon bigger + Blockly.Icon.prototype.renderIcon = function(cursorX) { + if (this.collapseHidden && this.block_.isCollapsed()) { + this.iconGroup_.setAttribute('display', 'none'); + return cursorX; + } + this.iconGroup_.setAttribute('display', 'block'); + + var SIZE = 1.7; + var TOP_MARGIN = 2; + var LEFT_MARGIN = 5; + var width = this.SIZE; + if (this.block_.RTL) { + cursorX -= width; + } + this.iconGroup_.setAttribute('transform', + 'translate(' + LEFT_MARGIN + ',' + TOP_MARGIN + ') scale(' + SIZE + ')'); + this.computeIconLocation(); + if (this.block_.RTL) { + cursorX -= Blockly.BlockSvg.SEP_SPACE_X; + } else { + cursorX += width + Blockly.BlockSvg.SEP_SPACE_X; + } + return cursorX; + }; + + // When mouse click occures on Blockly workspace + Blockly.utils.isRightButton = function(e) { + var target = e.target; + + // When control_if block is in use + if (controlBlockId != "") { + // When the user clicks anywhere outside the mutator and not on the mutator icon + if (!$(target).is('.blocklyBubbleCanvas') && !$(target).parents().is('.blocklyBubbleCanvas')) { + if (!$(target).is('.blocklyIconGroup') && !$(target).parents().is('.blocklyIconGroup')) { + // Hide the mutator + workspace.getBlockById(controlBlockId).mutator.setVisible(false); + } + } + } + // Disable right click on Blockly workspace + return false; + }; + + Blockly.Blocks['sumorobot_sleep'] = { + init: function() { + this.setColour("#E64C00"); + this.appendDummyInput() + .appendField("sleep") + .appendField(new Blockly.FieldTextInput('1000', + Blockly.FieldNumber.numberValidator), 'SLEEP'); + this.setPreviousStatement(true); + this.setNextStatement(true); + } + }; + + Blockly.Blocks['sumorobot_move'] = { + init: function() { + var OPERATORS = [ + ['move stop', 'STOP'], + ['move left', 'LEFT'], + ['move right', 'RIGHT'], + ['move search', 'SEARCH'], + ['move forward', 'FORWARD'], + ['move backward', 'BACKWARD'] + ]; + this.setColour("#E60000"); + var dropdown = new Blockly.FieldDropdown(OPERATORS); + this.appendDummyInput().appendField(dropdown, 'MOVE'); + this.setPreviousStatement(true); + this.setNextStatement(true); + } + }; + + Blockly.Blocks['sumorobot_opponent'] = { + init: function() { + this.setColour("#0099E6"); + this.appendDummyInput().appendField('opponent'); + this.setOutput(true, 'Boolean'); + } + }; + + Blockly.Blocks['sumorobot_line'] = { + init: function() { + var OPERATORS = [ + ['line left', 'LEFT'], + ['line right', 'RIGHT'] + ]; + this.setColour("#E6BF00"); + var dropdown = new Blockly.FieldDropdown(OPERATORS); + this.appendDummyInput().appendField(dropdown, 'LINE'); + this.setOutput(true, 'Boolean'); + } + }; + + Blockly.Python['sumorobot_sleep'] = function(block) { + var code = 'sumorobot.sleep(' + parseFloat(block.getFieldValue('SLEEP')) + ', "' + block.id + '")\n'; + return code; + }; + + Blockly.Python['sumorobot_move'] = function(block) { + var code = 'sumorobot.move(' + block.getFieldValue('MOVE') + ', "' + block.id + '")\n'; + return code; + }; + + Blockly.Python['sumorobot_opponent'] = function(block) { + var code = 'sumorobot.is_opponent("' + block.id + '")'; + return [code, Blockly.Python.ORDER_ATOMIC]; + }; + + Blockly.Python['sumorobot_line'] = function(block) { + var code = 'sumorobot.is_line(' + block.getFieldValue('LINE') + ', "' + block.id + '")'; + return [code, Blockly.Python.ORDER_ATOMIC]; + }; + + // Inject Blockly + var blocklyArea = document.getElementById('blocklyArea'); + var blocklyDiv = document.getElementById('blocklyDiv'); + var workspace = Blockly.inject(blocklyDiv, { + scrollbars: false, + media: 'assets/blockly/media/', + trashcan: true, + sounds: true, + zoom: { + controls: true, + startScale: 1.2 + }, + toolbox: document.getElementById('toolbox') + }); + + // On Blockly resize + var onresize = function(e) { + // Compute the absolute coordinates and dimensions of blocklyArea. + var element = blocklyArea; + var x = 0; + var y = 0; + do { + x += element.offsetLeft; + y += element.offsetTop; + element = element.offsetParent; + } while (element); + // Position blocklyDiv over blocklyArea + blocklyDiv.style.left = x + 'px'; + blocklyDiv.style.top = y + 'px'; + blocklyDiv.style.width = blocklyArea.offsetWidth + 'px'; + blocklyDiv.style.height = blocklyArea.offsetHeight + 'px'; + }; + window.addEventListener('resize', onresize, false); + onresize(); + Blockly.svgResize(workspace); + + // Retrieve the blocks + var xml = Blockly.Xml.textToDom(getLocalStorageItem("sumorobot.blockly")); + // Resume the blocks + Blockly.Xml.domToWorkspace(xml, workspace); + + // On Blockly code change + function onCodeChanged(event) { + // When the if condition block was created + if (event.type == Blockly.Events.CREATE && event.xml.getAttributeNode("type").nodeValue == "controls_if") { + // Remember the control_if block id + controlBlockId = event.blockId; + // Get the control_if block object + var block = workspace.getBlockById(event.blockId); + // When the control_if block doesn't already have an else + if (block.elseCount_ == 0) { + // Automatically add the else statement input + block.elseCount_ = 1; + block.updateShape_(); + } + // When the if condition block was removed + } else if (event.type == Blockly.Events.DELETE && event.oldXml.getAttributeNode("type").nodeValue == "controls_if") { + // Remove the control_if block id + controlBlockId = ""; + // Enable the if condition block + workspace.updateToolbox(document.getElementById("toolbox")); + } + + // Only process change and move commands + if (event.type != Blockly.Events.CHANGE && event.type != Blockly.Events.MOVE) return; + // Generate code from the used blocks + sumorobot.setBlocklyCode(Blockly.Python.workspaceToCode(workspace)); + + // Show the code in the ace editor, filter out block IDs + readOnlyCodingEditor.setValue("\n" + sumorobot.getBlocklyCode().replace(/[,]?[ ]?"(.*?)"/g, "")); + readOnlyCodingEditor.clearSelection(); + + // Save the code to the local storage + var xml = Blockly.Xml.workspaceToDom(workspace); + localStorage.setItem("sumorobot.blockly", Blockly.Xml.domToText(xml)); + + // When control_if block is used + if (controlBlockId != "") { + // Disable the if condition block + workspace.updateToolbox(document.getElementById("toolbox_no_if")); + } + } + + // Add a change listener to Blockly + workspace.addChangeListener(onCodeChanged); + + // Set a click listener on the document + $(document).click(function(e) { + var target = e.target; + + // When control_if block is in use + if (controlBlockId != "") { + // When the user clicks anywhere outside the mutator and not on the mutator icon + if (!$(target).is('.blocklyBubbleCanvas') && !$(target).parents().is('.blocklyBubbleCanvas')) { + if (!$(target).is('.blocklyIconGroup') && !$(target).parents().is('.blocklyIconGroup')) { + // Hide the mutator + workspace.getBlockById(controlBlockId).mutator.setVisible(false); + } + } + } + }); +});