// Custom Color Picker Blockly.FieldColour.COLOURS = [ '#ffffff', '#808000', '#ffff00', '#ff00ff', '#ff4500', '#c0c0c0', '#00ffff', '#00ff00', '#ff0000', '#ff1493', '#808080', '#0000ff', '#008000', '#800080', '#8a2be2', '#000000', '#000080', '#008080', '#800000', '#2e8b57' ]; Blockly.FieldColour.TITLES = [ 'white', 'olive', 'yellow', 'magenta', 'orangered', 'silver', 'aqua', 'lime', 'red', 'deeppink', 'gray', 'blue', 'green', 'purple', 'blueviolet', 'black', 'navy', 'teal', 'maroon', 'seagreen' ]; Blockly.FieldColour.COLUMNS = 5; /** Additional Basic Blocks********************************************************************************* */ var ugjCodecharDefinition = { "type": "ugj_codechar", "message0": "%{BKY_UGJ_CODECHAR_TITLE}", "args0": [ { "type": "input_value", "name": "code", "check": "Number" } ], "inputsInline": true, "output": "String", "tooltip": "%{BKY_UGJ_CODECHAR_TOOLTIP}", "helpUrl": "", "style": "text_blocks" }; Blockly.Blocks['ugj_codechar'] = { init: function () { this.jsonInit(ugjCodecharDefinition); } }; Blockly.JavaScript['ugj_codechar'] = function (block) { var value_code = Blockly.JavaScript.valueToCode(block, 'code', Blockly.JavaScript.ORDER_ATOMIC); var code = `String.fromCharCode(${value_code})`; return [code, Blockly.JavaScript.ORDER_NONE]; }; Blockly.Python['ugj_codechar'] = function (block) { var value_code = Blockly.Python.valueToCode(block, 'code', Blockly.Python.ORDER_ATOMIC); var code = `chr(${value_code})`; return [code, Blockly.Python.ORDER_NONE]; }; var ugjCharcodeDefinition = { "type": "ugj_charcode", "message0": "%{BKY_UGJ_CHARCODE_TITLE}", "args0": [ { "type": "input_value", "name": "char", "check": "String" } ], "inputsInline": true, "output": "Number", "tooltip": "%{BKY_UGJ_CHARCODE_TOOLTIP}", "helpUrl": "", "style": "text_blocks" }; Blockly.Blocks['ugj_charcode'] = { init: function () { this.jsonInit(ugjCharcodeDefinition); } }; Blockly.JavaScript['ugj_charcode'] = function (block) { var value_char = Blockly.JavaScript.valueToCode(block, 'char', Blockly.JavaScript.ORDER_ATOMIC); var code = `${value_char}.charCodeAt(0)`; return [code, Blockly.JavaScript.ORDER_NONE]; }; Blockly.Python['ugj_charcode'] = function (block) { var value_char = Blockly.Python.valueToCode(block, 'char', Blockly.Python.ORDER_ATOMIC); var code = `ord(${value_char})`; return [code, Blockly.Python.ORDER_NONE]; }; Blockly.Blocks['ugj_bintodec'] = { init: function () { this.appendValueInput("bin") .setCheck("String") .appendField("0b"); this.setInputsInline(true); this.setOutput(true, "Number"); this.setTooltip("2進数を10進数に変換します"); this.setHelpUrl(""); this.setStyle('math_blocks'); } }; Blockly.JavaScript['ugj_bintodec'] = function (block) { var value_bin = Blockly.JavaScript.valueToCode(block, 'bin', Blockly.JavaScript.ORDER_ATOMIC); var code = `parseInt (${value_bin}, 2)`; return [code, Blockly.JavaScript.ORDER_NONE]; }; Blockly.Python['ugj_bintodec'] = function (block) { var value_bin = Blockly.Python.valueToCode(block, 'bin', Blockly.Python.ORDER_ATOMIC); var code = `int(${value_bin}, 2)`; return [code, Blockly.Python.ORDER_NONE]; }; var ugjHextodecDefinition = { "type": "ugj_hextodec", "message0": "%{BKY_UGJ_HEXTODEC_TITLE}", "args0": [ { "type": "input_value", "name": "hex", "check": "String" } ], "inputsInline": true, "output": "Number", "tooltip": "%{BKY_UGJ_HEXTODEC_TOOLTIP}", "helpUrl": "", "style": "math_blocks" }; Blockly.Blocks['ugj_hextodec'] = { init: function () { this.jsonInit(ugjHextodecDefinition); } }; Blockly.JavaScript['ugj_hextodec'] = function (block) { var value_hex = Blockly.JavaScript.valueToCode(block, 'hex', Blockly.JavaScript.ORDER_ATOMIC); var code = `parseInt (${value_hex}, 16)`; return [code, Blockly.JavaScript.ORDER_ATOMIC]; }; Blockly.Python['ugj_hextodec'] = function (block) { var value_hex = Blockly.Python.valueToCode(block, 'hex', Blockly.Python.ORDER_ATOMIC); var code = `int(${value_hex}, 16)`; return [code, Blockly.Python.ORDER_NONE]; }; var ugjDectohexDefinition = { "type": "ugj_dectohex", "message0": "%{BKY_UGJ_DECTOHEX_TITLE}", "args0": [ { "type": "input_value", "name": "dec", "check": "Number" } ], "inputsInline": true, "output": "String", "tooltip": "%{BKY_UGJ_DECTOHEX_TOOLTIP}", "helpUrl": "", "style": "math_blocks" }; Blockly.Blocks['ugj_dectohex'] = { init: function () { this.jsonInit(ugjDectohexDefinition); } }; Blockly.JavaScript['ugj_dectohex'] = function (block) { var value_dec = Blockly.JavaScript.valueToCode(block, 'dec', Blockly.JavaScript.ORDER_ATOMIC); var code = `'0x' + (${value_dec}).toString(16).toUpperCase()`; return [code, Blockly.JavaScript.ORDER_NONE]; }; Blockly.Python['ugj_dectohex'] = function (block) { var value_dec = Blockly.Python.valueToCode(block, 'dec', Blockly.Python.ORDER_ATOMIC); var code = `f'{${value_dec}:#04x}'`; return [code, Blockly.Python.ORDER_NONE]; }; /** GPIO *****************************************************************************************************/ /************ */ /** GPIO Open */ /************ */ var ugjGpioOpenDefinition = { "type": "ugj_gpio_open", "message0": "%{BKY_GPIO_OPEN_TITLE}", "previousStatement": null, "nextStatement": null, "tooltip": "%{BKY_GPIO_OPEN_TOOLTIP}", "helpUrl": "", "style": "gpio_blocks" }; Blockly.Blocks['ugj_gpio_open'] = { init: function () { this.jsonInit(ugjGpioOpenDefinition); } }; Blockly.JavaScript['ugj_gpio_open'] = function (block) { Blockly.JavaScript.provideFunction_( 'require_gpio', [`const _pi = require('` + apptool.gpio_lib + `');`] ); var code = `await _pi.gpio_open();\n`; // return code; }; Blockly.Python['ugj_gpio_open'] = function (block) { Blockly.Python.provideFunction_( 'import_pin', ['from machine import Pin'] ); var code = `_pin = {}\n`; // return code; }; /************* */ /** GPIO Close */ /************* */ var ugjGpioCloseDefinition = { "type": "ugj_gpio_close", "message0": "%{BKY_GPIO_CLOSE_TITLE}", "previousStatement": null, "nextStatement": null, "tooltip": "%{BKY_GPIO_CLOSE_TOOLTIP}", "helpUrl": "", "style": "gpio_blocks" }; Blockly.Blocks['ugj_gpio_close'] = { init: function () { this.jsonInit(ugjGpioCloseDefinition); } }; Blockly.JavaScript['ugj_gpio_close'] = function (block) { var code = 'await _pi.gpio_close();\n'; return code; }; Blockly.Python['ugj_gpio_close'] = function (block) { var code = ''; return code; }; /*********************** */ /** GPIO Set Output ** */ /*********************** */ var ugjGpioSetOutputDefinition = { "type": "ugj_gpio_set_output", "message0": "%{BKY_GPIO_SET_OUTPUT_TITLE}", "args0": [ { "type": "input_value", "name": "gpio", "check": "Number" } ], "inputsInline": true, "previousStatement": null, "nextStatement": null, "tooltip": "%{BKY_GPIO_SET_OUTPUT_TOOLTIP}", "helpUrl": "", "style": "gpio_blocks" }; Blockly.Blocks['ugj_gpio_set_output'] = { init: function () { this.jsonInit(ugjGpioSetOutputDefinition); } }; Blockly.JavaScript['ugj_gpio_set_output'] = function (block) { var value_gpio = Blockly.JavaScript.valueToCode(block, 'gpio', Blockly.JavaScript.ORDER_ATOMIC); var code = `await _pi.gpio_set_output(${value_gpio});\n`; return code; }; Blockly.Python['ugj_gpio_set_output'] = function (block) { var value_gpio = Blockly.Python.valueToCode(block, 'gpio', Blockly.Python.ORDER_ATOMIC); var code = `_pin[${value_gpio}] = Pin(${value_gpio}, Pin.OUT)\n`; return code; }; /********************** */ /** GPIO Set Input ** */ /********************** */ var ugjGpioSetInputDefinition = { "type": "ugj_gpio_set_input", "message0": "%{BKY_GPIO_SET_INPUT_TITLE}", "args0": [ { "type": "input_value", "name": "gpio", "check": "Number" }, { "type": "field_dropdown", "name": "lflag", "options": [ [ "%{BKY_GPIO_SET_INPUT_PULLUP}", "PULL_UP" ], [ "%{BKY_GPIO_SET_INPUT_PULLDOWN}", "PULL_DOWN" ], [ "%{BKY_GPIO_SET_INPUT_PULLNONE}", "PULL_NONE" ] ] } ], "inputsInline": true, "previousStatement": null, "nextStatement": null, "tooltip": "%{BKY_GPIO_SET_INPUT_TOOLTIP}", "helpUrl": "", "style": "gpio_blocks" }; Blockly.Blocks['ugj_gpio_set_input'] = { init: function () { this.jsonInit(ugjGpioSetInputDefinition); } }; Blockly.JavaScript['ugj_gpio_set_input'] = function (block) { var value_gpio = Blockly.JavaScript.valueToCode(block, 'gpio', Blockly.JavaScript.ORDER_ATOMIC); var dropdown_lflag = block.getFieldValue('lflag'); var code = `await _pi.gpio_set_input(${value_gpio}, _pi.${dropdown_lflag});\n`; return code; }; Blockly.Python['ugj_gpio_set_input'] = function (block) { var value_gpio = Blockly.Python.valueToCode(block, 'gpio', Blockly.Python.ORDER_ATOMIC); var dropdown_lflag = block.getFieldValue('lflag'); let lflag; if (dropdown_lflag == 'PULL_NONE') { lflag = 'None'; } else { lflag = `Pin.${dropdown_lflag}`; } var code = `_pin[${value_gpio}] = Pin(${value_gpio}, Pin.IN, ${lflag})\n`; return code; }; /********************* */ /** Read GPIO Value ** */ /***********************/ var ugjGpioReadDefinition = { "type": "ugj_gpio_read", "message0": "%{BKY_GPIO_READ_TITLE}", "args0": [ { "type": "input_value", "name": "gpio", "check": "Number" } ], "inputsInline": true, "output": "Number", "tooltip": "%{BKY_GPIO_READ_TOOLTIP", "helpUrl": "", "style": "gpio_blocks" }; Blockly.Blocks['ugj_gpio_read'] = { init: function () { this.jsonInit(ugjGpioReadDefinition); } }; Blockly.JavaScript['ugj_gpio_read'] = function (block) { var value_gpio = Blockly.JavaScript.valueToCode(block, 'gpio', Blockly.JavaScript.ORDER_ATOMIC); var code = `await _pi.gpio_read(${value_gpio})`; return [code, Blockly.JavaScript.ORDER_NONE]; }; Blockly.Python['ugj_gpio_read'] = function (block) { var value_gpio = Blockly.Python.valueToCode(block, 'gpio', Blockly.Python.ORDER_ATOMIC); var code = `_pin[${value_gpio}].value()`; return [code, Blockly.Python.ORDER_NONE]; }; /*******************************************/ /** GPIO Write Value - Common GPIO on/off **/ /*******************************************/ var ugjGpioWriteDefinition = { "type": "ugj_gpio_write", "message0": "%{BKY_GPIO_WRITE_TITLE}", "args0": [ { "type": "input_value", "name": "gpio", "check": "Number" }, { "type": "field_dropdown", "name": "level", "options": [ [ "0", "0" ], [ "1", "1" ] ] } ], "inputsInline": true, "previousStatement": null, "nextStatement": null, "tooltip": "%{BKY_GPIO_WRITE_TOOLTIP}", "helpUrl": "", "style": "gpio_blocks" }; Blockly.Blocks['ugj_gpio_write'] = { init: function () { this.jsonInit(ugjGpioWriteDefinition); } }; Blockly.JavaScript['ugj_gpio_write'] = function (block) { var value_gpio = Blockly.JavaScript.valueToCode(block, 'gpio', Blockly.JavaScript.ORDER_ATOMIC); var dropdown_level = block.getFieldValue('level'); var code = `await _pi.gpio_write(${value_gpio}, ${dropdown_level});\n`; return code; }; Blockly.Python['ugj_gpio_write'] = function (block) { var value_gpio = Blockly.Python.valueToCode(block, 'gpio', Blockly.Python.ORDER_ATOMIC); var dropdown_level = block.getFieldValue('level'); var code = `_pin[${value_gpio}].value(${dropdown_level})\n`; return code; }; /*****************/ /** Servo motor **/ /*****************/ var ugjServoDefinition = { "type": "ugj_servo", "message0": "%{BKY_SERVO_TITLE}", "args0": [ { "type": "input_value", "name": "gpio", "check": "Number" }, { "type": "input_value", "name": "pulsewidth", "check": "Number" } ], "inputsInline": true, "previousStatement": null, "nextStatement": null, "tooltip": "%{BKY_SERVO_TOOLTIP}", "helpUrl": "", "style": "gpio_blocks" }; Blockly.Blocks['ugj_servo'] = { init: function () { this.jsonInit(ugjServoDefinition); } }; Blockly.JavaScript['ugj_servo'] = function (block) { var value_gpio = Blockly.JavaScript.valueToCode(block, 'gpio', Blockly.JavaScript.ORDER_ATOMIC); var value_pulsewidth = Blockly.JavaScript.valueToCode(block, 'pulsewidth', Blockly.JavaScript.ORDER_ATOMIC); var code = `await _pi.servo(${value_gpio}, ${value_pulsewidth});\n`; return code; }; // Blockly.Python['ugj_servo'] = function (block) { // var value_gpio = Blockly.Python.valueToCode(block, 'gpio', Blockly.Python.ORDER_ATOMIC); // var value_pulsewidth = Blockly.Python.valueToCode(block, 'pulsewidth', Blockly.Python.ORDER_ATOMIC); // var code = `await pi.servo(gpioHand, ${value_gpio}, ${value_pulsewidth})\n`; // return code; // }; /************************************************* */ /** starts software timed PWM on an output GPIO ** */ /************************************************* */ var ugjPwmDefinition = { "type": "ugj_pwm", "message0": "%{BKY_PWM_TITLE}", "args0": [ { "type": "input_value", "name": "gpio", "check": "Number" }, { "type": "input_value", "name": "pwm_frequency", "check": "Number" } ], "inputsInline": true, "previousStatement": null, "nextStatement": null, "tooltip": "%{BKY_PWM_TOOLTIP}", "helpUrl": "", "style": "gpio_blocks" }; Blockly.Blocks['ugj_pwm'] = { init: function () { this.jsonInit(ugjPwmDefinition); } }; // Blockly.JavaScript['ugj_pwm'] = function (block) { // var value_gpio = Blockly.JavaScript.valueToCode(block, 'gpio', Blockly.JavaScript.ORDER_ATOMIC); // var value_pwm_frequency = Blockly.JavaScript.valueToCode(block, 'pwm_frequency', Blockly.JavaScript.ORDER_ATOMIC); // var value_pwm_duty_cycle = Blockly.JavaScript.valueToCode(block, 'pwm_duty_cycle', Blockly.JavaScript.ORDER_ATOMIC); // var code = `await _pi.pwm(${value_gpio}, ${value_pwm_frequency}, ${value_pwm_duty_cycle});\n`; // return code; // }; Blockly.Python['ugj_pwm'] = function (block) { var value_gpio = Blockly.Python.valueToCode(block, 'gpio', Blockly.Python.ORDER_ATOMIC); var value_pwm_frequency = Blockly.Python.valueToCode(block, 'pwm_frequency', Blockly.Python.ORDER_ATOMIC); var value_pwm_duty_cycle = Blockly.Python.valueToCode(block, 'pwm_duty_cycle', Blockly.Python.ORDER_ATOMIC); Blockly.Python.provideFunction_( 'import_pwm', ['from machine import PWM'] ); var code = `_pin[${value_gpio}] = PWM(Pin(${value_gpio})) _pin[${value_gpio}].freq(${value_pwm_frequency}) `; // var code = `await pi.pwm(gpioHand, ${value_gpio}, ${value_pwm_frequency}, ${value_pwm_duty_cycle})\n`; return code; }; Blockly.Blocks['oc_pwm_duty'] = { init: function () { this.appendValueInput("gpio") .setCheck("Number") .appendField("GPIO"); this.appendValueInput("duty") .setCheck("Number") .appendField("へデューティ値"); this.appendDummyInput() .appendField("でパルスを出力"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setTooltip("PWM出力に設定したGPIOへパルスを出力します。デューティ値は 0(0%) ~ 65535(100%) の範囲で指定します。"); this.setHelpUrl(""); this.setStyle('gpio_blocks'); } }; Blockly.Python['oc_pwm_duty'] = function (block) { var value_gpio = Blockly.Python.valueToCode(block, 'gpio', Blockly.Python.ORDER_ATOMIC); var value_duty = Blockly.Python.valueToCode(block, 'duty', Blockly.Python.ORDER_ATOMIC); var code = `_pin[${value_gpio}].duty_u16(${value_duty})\n`; return code; }; /********************** */ /** Open Serial Port ** */ /********************** */ var ugjSerialOpenDefinition = { "type": "ugj_serial_open", "message0": "%{BKY_SERIAL_OPEN_TITLE}", "args0": [ { "type": "field_dropdown", "name": "baud", "options": [ [ "9600", "9600" ], [ "19200", "19200" ], [ "115200", "115200" ] ] } ], "inputsInline": true, "previousStatement": null, "nextStatement": null, "tooltip": "%{BKY_SERIAL_OPEN_TOOLTIP}", "helpUrl": "", "style": "gpio_blocks" }; Blockly.Blocks['ugj_serial_open'] = { init: function () { this.jsonInit(ugjSerialOpenDefinition); } }; Blockly.JavaScript['ugj_serial_open'] = function (block) { // var value_tty = Blockly.JavaScript.valueToCode(block, 'tty', Blockly.JavaScript.ORDER_ATOMIC); var dropdown_baud = block.getFieldValue('baud'); Blockly.JavaScript.provideFunction_( 'require_gpio', [`const _pi = require('` + apptool.gpio_lib + `');`] ); var code = `await _pi.serial_open('/dev/ttyS0', ${dropdown_baud});\n`; // var code = `await _pi.serial_open('/dev/serial0', ${dropdown_baud});\n`; return code; }; // Blockly.Python['ugj_serial_open'] = function (block) { // var value_tty = Blockly.Python.valueToCode(block, 'tty', Blockly.Python.ORDER_ATOMIC); // var dropdown_baud = block.getFieldValue('baud'); // Blockly.Python.provideFunction_( // 'import_lgpio', ['import lgpio as pi'] // ); // var code = `ser_hand = pi.serial_open(${value_tty}, ${dropdown_baud}, 0)\n`; // return code; // }; /*********************** */ /** Close Serial Port ** */ /*********************** */ var ugjSerialCloseDefinition = { "type": "ugj_serial_close", "message0": "%{BKY_SERIAL_CLOSE_TITLE}", "inputsInline": true, "previousStatement": null, "nextStatement": null, "tooltip": "%{BKY_SERIAL_CLOSE_TOOLTIP}", "helpUrl": "", "style": "gpio_blocks" }; Blockly.Blocks['ugj_serial_close'] = { init: function () { this.jsonInit(ugjSerialCloseDefinition); } }; Blockly.JavaScript['ugj_serial_close'] = function (block) { var code = 'await _pi.serial_close();\n'; return code; }; // Blockly.Python['ugj_serial_close'] = function (block) { // var code = 'pi.serial_close(ser_hand)\n'; // return code; // }; /************************** */ /** Write Data to Serial ** */ /************************** */ var ugjSerialWriteDefinition = { "type": "ugj_serial_write", "message0": "%{BKY_SERIAL_WRITE_TITLE}", "args0": [ { "type": "input_value", "name": "data", "check": "String" } ], "inputsInline": true, "previousStatement": null, "nextStatement": null, "tooltip": "%{BKY_SERIAL_WRITE_TOOLTIP}", "helpUrl": "", "style": "gpio_blocks" }; Blockly.Blocks['ugj_serial_write'] = { init: function () { this.jsonInit(ugjSerialWriteDefinition); } }; Blockly.JavaScript['ugj_serial_write'] = function (block) { var value_data = Blockly.JavaScript.valueToCode(block, 'data', Blockly.JavaScript.ORDER_ATOMIC); var code = `await _pi.serial_write(${value_data});\n`; return code; }; // Blockly.Python['ugj_serial_write'] = function (block) { // var value_data = Blockly.Python.valueToCode(block, 'data', Blockly.Python.ORDER_ATOMIC); // var code = `await pi.serial_write(ser_hand, ${value_data}.encode())\n`; // return code; // }; /************************ */ /** Read Data from Serial */ /************************ */ var ugjSerialReadDefinition = { "type": "ugj_serial_read", "message0": "%{BKY_SERIAL_READ_TITLE}", "args0": [ { "type": "input_value", "name": "count", "check": "Number" } ], "inputsInline": true, "output": null, "tooltip": "%{BKY_SERIAL_READ_TOOLTIP}", "helpUrl": "", "style": "gpio_blocks" }; Blockly.Blocks['ugj_serial_read'] = { init: function () { this.jsonInit(ugjSerialReadDefinition); } }; Blockly.JavaScript['ugj_serial_read'] = function (block) { var value_count = Blockly.JavaScript.valueToCode(block, 'count', Blockly.JavaScript.ORDER_ATOMIC); var code = `await _pi.serial_read(${value_count})`; return [code, Blockly.JavaScript.ORDER_ATOMIC]; }; // Blockly.Python['ugj_serial_read'] = function (block) { // var value_count = Blockly.Python.valueToCode(block, 'count', Blockly.Python.ORDER_ATOMIC); // var code = `await pi.serial_read(ser_hand, ${value_count}).decode()`; // return [code, Blockly.Python.ORDER_ATOMIC]; // }; /********************* */ /** Open I2C Device ** */ /********************* */ var ugjI2cOpenDefinition = { "type": "ugj_i2c_open", "message0": "%{BKY_I2C_OPEN_TITLE}", "args0": [ { "type": "input_value", "name": "i2c_address", "check": "Number" } ], "inputsInline": true, "previousStatement": null, "nextStatement": null, "tooltip": "%{BKY_I2C_OPEN_TOOLTIP}", "helpUrl": "", "style": "gpio_blocks" }; Blockly.Blocks['ugj_i2c_open'] = { init: function () { this.jsonInit(ugjI2cOpenDefinition); } }; Blockly.JavaScript['ugj_i2c_open'] = function (block) { var value_i2c_address = Blockly.JavaScript.valueToCode(block, 'i2c_address', Blockly.JavaScript.ORDER_ATOMIC); Blockly.JavaScript.provideFunction_( 'require_gpio', [`const _pi = require('` + apptool.gpio_lib + `');`] ); var code = `await _pi.i2c_open(${apptool.i2c_bus}, ${value_i2c_address});\n`; return code; }; Blockly.Python['ugj_i2c_open'] = function (block) { var value_i2c_address = Blockly.Python.valueToCode(block, 'i2c_address', Blockly.Python.ORDER_ATOMIC); Blockly.Python.provideFunction_( 'import_i2c', ['from machine import I2C'] ); var code = `_addr = ${value_i2c_address} _i2c_hand = I2C(0,sda=Pin(0),scl=Pin(1))\n`; return code; }; /********************** */ /** Close I2C Device ** */ /********************** */ var ugjI2cCloseDefinition = { "type": "ugj_i2c_close", "message0": "%{BKY_I2C_CLOSE_TITLE}", "inputsInline": true, "previousStatement": null, "nextStatement": null, "tooltip": "%{BKY_I2C_CLOSE_TOOLTIP}", "helpUrl": "", "style": "gpio_blocks" }; Blockly.Blocks['ugj_i2c_close'] = { init: function () { this.jsonInit(ugjI2cCloseDefinition); } }; Blockly.JavaScript['ugj_i2c_close'] = function (block) { var code = `await _pi.i2c_close();\n`; return code; }; Blockly.Python['ugj_i2c_close'] = function (block) { var code = ``; return code; }; /*************************************** */ /** Sends a single byte to the device ** */ /*************************************** */ Blockly.Blocks['oc_i2c_write_byte'] = { init: function () { this.appendValueInput("byte_val") .setCheck("Number") .appendField("デバイスに1バイトデータ"); this.appendDummyInput() .appendField("を送信"); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setTooltip("i2cデバイスに1バイトデータを送信します。0-0xFF(255)の範囲の数字で入力してください。"); this.setHelpUrl(""); this.setStyle('gpio_blocks'); } }; Blockly.JavaScript['oc_i2c_write_byte'] = function (block) { var value_byte_val = Blockly.JavaScript.valueToCode(block, 'byte_val', Blockly.JavaScript.ORDER_ATOMIC); // TODO: Assemble JavaScript into code variable. var code = `await _pi.i2c_write_byte(${value_byte_val});\n`; return code; }; /****************************************************************** */ /** Writes a single byte to the specified register of the device ** */ /****************************************************************** */ var ugjI2cWriteByteDataDefinition = { "type": "ugj_i2c_write_byte_data", "message0": "%{BKY_I2C_WRITE_BYTE_DATA_TITLE}", "args0": [ { "type": "input_value", "name": "reg", "check": "Number" }, { "type": "input_value", "name": "byte_val", "check": "Number" } ], "inputsInline": true, "previousStatement": null, "nextStatement": null, "tooltip": "%{BKY_I2C_WRITE_BYTE_DATA_TOOLTIP}", "helpUrl": "", "style": "gpio_blocks" }; Blockly.Blocks['ugj_i2c_write_byte_data'] = { init: function () { this.jsonInit(ugjI2cWriteByteDataDefinition); } }; Blockly.JavaScript['ugj_i2c_write_byte_data'] = function (block) { var value_reg = Blockly.JavaScript.valueToCode(block, 'reg', Blockly.JavaScript.ORDER_ATOMIC); var value_byte_val = Blockly.JavaScript.valueToCode(block, 'byte_val', Blockly.JavaScript.ORDER_ATOMIC); var code = `await _pi.i2c_write_byte_data(${value_reg}, ${value_byte_val});\n`; return code; }; Blockly.Python['ugj_i2c_write_byte_data'] = function (block) { var value_reg = Blockly.Python.valueToCode(block, 'reg', Blockly.Python.ORDER_ATOMIC); var value_byte_val = Blockly.Python.valueToCode(block, 'byte_val', Blockly.Python.ORDER_ATOMIC); var code = `_i2c_hand.writeto_mem(_addr, ${value_reg}, (${value_byte_val}).to_bytes(1,'big'))\n`; return code; }; /****************************************************************** */ /** Read a single byte from the specified resister of the device ** */ /****************************************************************** */ var ugjI2cReadByteDataDefinition = { "type": "ugj_i2c_read_byte_data", "message0": "%{BKY_I2C_READ_BYTE_DATA_TITLE}", "args0": [ { "type": "input_value", "name": "reg", "check": "Number" } ], "inputsInline": true, "output": null, "tooltip": "%{BKY_I2C_READ_BYTE_DATA_TOOLTIP}", "helpUrl": "", "style": "gpio_blocks" }; Blockly.Blocks['ugj_i2c_read_byte_data'] = { init: function () { this.jsonInit(ugjI2cReadByteDataDefinition); } }; Blockly.JavaScript['ugj_i2c_read_byte_data'] = function (block) { var value_reg = Blockly.JavaScript.valueToCode(block, 'reg', Blockly.JavaScript.ORDER_ATOMIC); var code = `await _pi.i2c_read_byte_data(${value_reg})`; return [code, Blockly.JavaScript.ORDER_ATOMIC]; }; Blockly.Python['ugj_i2c_read_byte_data'] = function (block) { var value_reg = Blockly.Python.valueToCode(block, 'reg', Blockly.Python.ORDER_ATOMIC); var code = `int.from_bytes(_i2c_hand.readfrom_mem(_addr, ${value_reg}, 1), 'big')\n`; return [code, Blockly.Python.ORDER_ATOMIC]; }; Blockly.Blocks['ugj_i2c_read_word_data'] = { init: function () { this.appendValueInput("reg") .setCheck("Number") .appendField("レジスタ"); this.appendDummyInput() .appendField("のワード値"); this.setInputsInline(true); this.setOutput(true, "Number"); this.setStyle('gpio_blocks'); this.setTooltip("デバイスの指定レジスタからワードデータを読み出します。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_i2c_read_word_data'] = function (block) { var value_reg = Blockly.JavaScript.valueToCode(block, 'reg', Blockly.JavaScript.ORDER_ATOMIC); var code = `await _pi.i2c_read_word_data(${value_reg})`; return [code, Blockly.JavaScript.ORDER_ATOMIC]; }; var ugjI2cWriteI2cBlockDataDefinition = { "type": "ugj_i2c_write_i2c_block_data", "message0": "%{BKY_I2C_WRITE_I2C_BLOCK_DATA_TITLE}", "args0": [ { "type": "input_value", "name": "reg", "check": "Number" }, { "type": "input_value", "name": "data", "check": "String" } ], "inputsInline": true, "previousStatement": null, "nextStatement": null, "tooltip": "%{BKY_I2C_WRITE_I2C_BLOCK_DATA_TOOLTIP}", "helpUrl": "", "style": "gpio_blocks" }; Blockly.Blocks['ugj_i2c_write_i2c_block_data'] = { init: function () { this.jsonInit(ugjI2cWriteI2cBlockDataDefinition); } }; Blockly.JavaScript['ugj_i2c_write_i2c_block_data'] = function (block) { var value_reg = Blockly.JavaScript.valueToCode(block, 'reg', Blockly.JavaScript.ORDER_ATOMIC); var value_data = Blockly.JavaScript.valueToCode(block, 'data', Blockly.JavaScript.ORDER_ATOMIC); var code = `await _pi.i2c_write_i2c_block_data (${value_reg}, ${value_data});`; return code; }; Blockly.Python['ugj_i2c_write_i2c_block_data'] = function (block) { var value_reg = Blockly.Python.valueToCode(block, 'reg', Blockly.Python.ORDER_ATOMIC); var value_data = Blockly.Python.valueToCode(block, 'data', Blockly.Python.ORDER_ATOMIC); var code = `_i2c_hand.writeto_mem(_addr, ${value_reg}, bytearray(${value_data}))\n`; return code; }; /************************************************************************** */ /** Returns count bytes read from the raw device associated with handle. ** */ /************************************************************************** */ var ugjI2cReadDeviceDefinition = { "type": "ugj_i2c_read_device", "message0": "%{BKY_I2C_READ_DEVICE_TITLE}", "args0": [ { "type": "input_value", "name": "count", "check": "Number" } ], "inputsInline": true, "output": null, "tooltip": "%{BKY_I2C_READ_DEVICE_TOOLTIP}", "helpUrl": "", "style": "gpio_blocks" }; Blockly.Blocks['ugj_i2c_read_device'] = { init: function () { this.jsonInit(ugjI2cReadDeviceDefinition); } }; Blockly.JavaScript['ugj_i2c_read_device'] = function (block) { var value_count = Blockly.JavaScript.valueToCode(block, 'count', Blockly.JavaScript.ORDER_ATOMIC); var code = `await _pi.i2c_read_device(${value_count})`; return [code, Blockly.JavaScript.ORDER_ATOMIC]; }; // Blockly.Python['ugj_i2c_read_device'] = function (block) { // var value_count = Blockly.Python.valueToCode(block, 'count', Blockly.Python.ORDER_ATOMIC); // var code = `await pi.i2c_read_device(i2c_hand, ${value_count}).decode()`; // return [code, Blockly.Python.ORDER_ATOMIC]; // }; /********************************************** */ /** Writes the data bytes to the raw device. ** */ /********************************************** */ var ugjI2cWriteDeviceDefinition = { "type": "ugj_i2c_write_device", "message0": "%{BKY_I2C_WRITE_DEVICE_TITLE}", "args0": [ { "type": "input_value", "name": "data", "check": "String" } ], "inputsInline": true, "previousStatement": null, "nextStatement": null, "tooltip": "%{BKY_I2C_WRITE_DEVICE_TOOLTIP}", "helpUrl": "", "style": "gpio_blocks" }; Blockly.Blocks['ugj_i2c_write_device'] = { init: function () { this.jsonInit(ugjI2cWriteDeviceDefinition); } }; Blockly.JavaScript['ugj_i2c_write_device'] = function (block) { var value_data = Blockly.JavaScript.valueToCode(block, 'data', Blockly.JavaScript.ORDER_ATOMIC); var code = `await _pi.i2c_write_device(${value_data})\n`; return code; }; // Blockly.Python['ugj_i2c_write_device'] = function (block) { // var value_data = Blockly.Python.valueToCode(block, 'data', Blockly.Python.ORDER_ATOMIC); // var code = `await pi.i2c_write_device(i2c_hand, ${value_data}.encode())\n`; // return code; // }; /** Multimedia *****************************************************************************************************/ /******************** */ /** Face Detection ** */ /******************** */ Blockly.Blocks['ugj_face_init'] = { init: function () { this.appendDummyInput() .appendField("顔検出を開始"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setStyle('multimedia_blocks'); this.setTooltip("Blazeface detector モデルによる顔検出を開始します。最初に実行してください"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_face_init'] = function (block) { Blockly.JavaScript.provideFunction_( 'require_tfjs', [`const _tf = require('@tensorflow/tfjs-node');`] ); Blockly.JavaScript.provideFunction_( 'require_blazeface', [`const _blazeface = require('@tensorflow-models/blazeface');`] ); var code = [ "const _videoEl = document.getElementById('subdisplay');", `const _displaySize = { width: _videoEl.width, height: _videoEl.height };`, "const _stream = await navigator.mediaDevices.getUserMedia({ audio: false, video: _displaySize });", "_videoEl.srcObject = _stream;", `const _model = await _blazeface.load();`, "" ].join('\n'); return code; }; Blockly.Blocks['ugj_face_display'] = { init: function () { this.appendDummyInput() .appendField("顔検出ビデオを表示"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setStyle('multimedia_blocks'); this.setTooltip("カメラの映像を画像エリアに表示します。必須ではないブロックです。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_face_display'] = function (block) { var code = [ "_videoEl.style.display = 'inline-block';", `const _overlay = document.createElement('canvas');`, `_overlay.setAttribute('width', _videoEl.width);`, `_overlay.setAttribute('height', _videoEl.height);`, `_overlay.className = 'subdisplay';`, `document.getElementById('display_area').appendChild(_overlay);`, `const _overlay_ctx = _overlay.getContext('2d');`, "" ].join('\n'); return code; }; Blockly.Blocks['ugj_face_detect'] = { init: function () { this.appendValueInput("preditions") .setCheck("Variable") .appendField("顔検出を実行し、結果をリスト"); this.appendDummyInput() .appendField("に代入する"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setTooltip("顔検出を実行します。検出結果はリストになります。顔の位置は「顔の座標」ブロックで参照します。"); this.setHelpUrl(""); this.setStyle('multimedia_blocks'); } }; Blockly.JavaScript['ugj_face_detect'] = function (block) { var value_preditions = Blockly.JavaScript.valueToCode(block, 'preditions', Blockly.JavaScript.ORDER_ATOMIC); var code = `${value_preditions} = await _model.estimateFaces(_videoEl, false);`; return code; }; Blockly.Blocks['ugj_face_location'] = { init: function () { this.appendValueInput("prediction") .setCheck("Array") .appendField("顔"); this.appendDummyInput() .appendField("の") .appendField(new Blockly.FieldDropdown([["左座標", "topLeft[0]"], ["上座標", "topLeft[1]"], ["右座標", "bottomRight[0]"], ["下座標", "bottomRight[1]"]]), "member"); this.setInputsInline(true); this.setOutput(true, "Number"); this.setTooltip("顔検出結果の座標を参照します。"); this.setHelpUrl(""); this.setStyle('multimedia_blocks'); } }; Blockly.JavaScript['ugj_face_location'] = function (block) { var value_prediction = Blockly.JavaScript.valueToCode(block, 'prediction', Blockly.JavaScript.ORDER_NONE); var dropdown_member = block.getFieldValue('member'); var code = `${value_prediction}.${dropdown_member}`; return [code, Blockly.JavaScript.ORDER_NONE]; }; Blockly.Blocks['ugj_face_draw'] = { init: function () { this.appendValueInput("prediction") .setCheck("Variable") .appendField("顔"); this.appendDummyInput() .appendField("を描画:") .appendField(new Blockly.FieldCheckbox("TRUE"), "with_landmark") .appendField("ランドマーク"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setTooltip("顔検出結果をビデオ画面に描画します。「ビデオを表示」ブロックが必要です。"); this.setHelpUrl(""); this.setStyle('multimedia_blocks'); } }; Blockly.JavaScript['ugj_face_draw'] = function (block) { var value_prediction = Blockly.JavaScript.valueToCode(block, 'prediction', Blockly.JavaScript.ORDER_NONE); var checkbox_with_landmark = block.getFieldValue('with_landmark') === 'TRUE'; var code = `const _start = ${value_prediction}.topLeft; const _end = ${value_prediction}.bottomRight; const _size = [_end[0] - _start[0], _end[1] - _start[1]]; _overlay_ctx.clearRect(0, 0, _displaySize.width, _displaySize.height) _overlay_ctx.fillStyle = 'rgba(255, 0, 0, 0.5)'; _overlay_ctx.fillRect(_start[0], _start[1], _size[0], _size[1]); if (${checkbox_with_landmark}) { const _landmarks = ${value_prediction}.landmarks; _overlay_ctx.fillStyle = 'blue'; for (let _j = 0; _j < _landmarks.length; _j++) { const _x = _landmarks[_j][0]; const _y = _landmarks[_j][1]; _overlay_ctx.fillRect(_x, _y, 5, 5); } } `; return code; }; /******************************* */ /** Speech Commands Recognizer * */ /******************************* */ Blockly.Blocks['oc_speechcommands_init'] = { init: function () { this.appendDummyInput() .appendField("音声コマンド認識を開始"); this.appendValueInput("custom_model") .setCheck("String") .setAlign(Blockly.ALIGN_RIGHT) .appendField("カスタムモデル"); this.appendDummyInput() .setAlign(Blockly.ALIGN_RIGHT) .appendField(new Blockly.FieldVariable("ラベル"), "classlabels") .appendField("を取得"); this.setInputsInline(false); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setTooltip("Tensorflow 音声コマンド認識モデルを初期化します。Google Teachable Machine で作成したカスタムモデルのフォルダパスを指定します。モデルに含まれるラベルのリストを取得し変数に代入します。"); this.setHelpUrl(""); this.setStyle('multimedia_blocks'); } }; Blockly.JavaScript['oc_speechcommands_init'] = function (block) { var value_custom_model = Blockly.JavaScript.valueToCode(block, 'custom_model', Blockly.JavaScript.ORDER_NONE); var variable_classlabels = Blockly.JavaScript.nameDB_.getName(block.getFieldValue('classlabels'), Blockly.Names.NameType.VARIABLE); Blockly.JavaScript.provideFunction_( 'require_tfjs', [`const _tf = require('@tensorflow/tfjs-node');`] ); Blockly.JavaScript.provideFunction_( 'require_speechcommands', [`const _speechcommands = require('@tensorflow-models/speech-commands');`] ); // Check empty let cp = undefined, md = undefined; if (value_custom_model != "''") { let cm = value_custom_model.replace(/(^'|'$)/g, ''); cp = `'file://${apptool.path.join(cm, 'model.json')}'`; md = `'file://${apptool.path.join(cm, 'metadata.json')}'`; } var code = `const _checkpointURL = ${cp}; const _metadataURL = ${md}; const _recognizer = _speechcommands.create( "BROWSER_FFT", undefined, _checkpointURL, _metadataURL); await _recognizer.ensureModelLoaded(); ${variable_classlabels} = _recognizer.wordLabels(); `; return code; }; Blockly.Blocks['oc_speechcommand_listen'] = { init: function () { this.appendDummyInput() .appendField("音声コマンドを認識したら"); this.appendDummyInput() .setAlign(Blockly.ALIGN_RIGHT) .appendField(new Blockly.FieldVariable("スコア"), "scores") .appendField("を取得"); this.appendStatementInput("do") .setCheck(null); this.appendDummyInput() .setAlign(Blockly.ALIGN_RIGHT) .appendField("オーバーラップ係数") .appendField(new FieldSlider(0.5, 0, 1, 0.05), "overlapFactor"); this.appendDummyInput() .setAlign(Blockly.ALIGN_RIGHT) .appendField("スコアしきい値") .appendField(new FieldSlider(0.75, 0, 1, 0.05), "probabilityThreshold"); this.setInputsInline(false); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setTooltip("音声コマンドを認識するとステートメントを実行します。「スコア」は「ラベル」に対応するリストです。"); this.setHelpUrl(""); this.setStyle('multimedia_blocks'); } }; Blockly.JavaScript['oc_speechcommand_listen'] = function (block) { var variable_scores = Blockly.JavaScript.nameDB_.getName(block.getFieldValue('scores'), Blockly.Names.NameType.VARIABLE); var statements_do = Blockly.JavaScript.statementToCode(block, 'do'); var number_probabilitythreshold = block.getFieldValue('probabilityThreshold'); var number_overlapfactor = block.getFieldValue('overlapFactor'); var code = `_recognizer.listen(_result => { ${variable_scores} = _result.scores; ${statements_do} }, { overlapFactor: ${number_overlapfactor}, probabilityThreshold: ${number_probabilitythreshold} }); `; return code; }; /**************************** */ /** Say while some seconds ** */ /**************************** */ Blockly.Blocks['ugj_canvas_say'] = { init: function () { this.appendValueInput("say") .setCheck(null); this.appendDummyInput() .appendField("と") .appendField(new FieldSlider(2, 0, 30, 1), "sec") .appendField("秒言う"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setStyle('multimedia_blocks') this.setTooltip("キャンバスにフキダシを作ります。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_canvas_say'] = function (block) { var value_say = Blockly.JavaScript.valueToCode(block, 'say', Blockly.JavaScript.ORDER_ATOMIC); var value_sec = block.getFieldValue('sec'); var code = [ `_fukidashi(String(${value_say}), ${value_sec});`, '' ].join('\n'); return code; }; Blockly.Python['ugj_canvas_say'] = function (block) { var value_say = Blockly.Python.valueToCode(block, 'say', Blockly.Python.ORDER_ATOMIC); var value_sec = Blockly.Python.valueToCode(block, 'sec', Blockly.Python.ORDER_ATOMIC); var code = `print(${value_say})\n`; return code; }; /*************************** */ /** Canvas Initialization ** */ /*************************** */ var ugj_canvas_init_definition = { "type": "ugj_canvas_init", "message0": "%{BKY_UGJ_CANVAS_INIT_TITLE}", "previousStatement": null, "nextStatement": null, "tooltip": "%{BKY_UGJ_CANVAS_INIT_TOOLTIP}", "helpUrl": "", "style": "multimedia_blocks" } Blockly.Blocks['ugj_canvas_init'] = { init: function () { this.jsonInit(ugj_canvas_init_definition); } }; Blockly.JavaScript['ugj_canvas_init'] = function (block) { var code = [ `let _canvas = document.getElementById('gcanvas');`, `_canvas.style.display = 'inline-block';`, "let _ctx = _canvas.getContext('2d');", '' ].join('\n'); return code; }; /************************* */ /** Canvas Finalization ** */ /************************* */ Blockly.Blocks['ugj_canvas_finalize'] = { init: function () { this.appendDummyInput() .appendField("キャンバスを片付ける"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setStyle('multimedia_blocks') this.setTooltip("使ったキャンバスを片付けます。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_canvas_finalize'] = function (block) { var code = `document.getElementById('gcanvas').style.display = 'none';\n`; return code; }; /**************************** */ /** Load Image File to Canvas */ /**************************** */ Blockly.Blocks['ugj_canvas_loadimg'] = { init: function () { this.appendValueInput("imgfilename") .setCheck("String") .appendField("ファイル名"); this.appendDummyInput() .appendField("の画像をキャンバスに描画"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setStyle('multimedia_blocks') this.setTooltip("画像ファイルの内容をキャンバス上にロードします。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_canvas_loadimg'] = function (block) { var value_imgfilename = Blockly.JavaScript.valueToCode(block, 'imgfilename', Blockly.JavaScript.ORDER_ATOMIC); var code = [ `let _img = new Image();`, `_img.src = '${apptool.doc_root}' + ${value_imgfilename};`, `_img.onload = () => _ctx.drawImage(img,0,0);`, // `ugj_canvasImg('${ugj_const.doc_root}' + ${value_imgfilename});`, '' ].join('\n'); return code; }; /**************** */ /** Clear Rect ** */ /**************** */ Blockly.Blocks['ugj_canvas_clearrect'] = { init: function () { this.appendValueInput("x") .setCheck("Number") .appendField("長方形に消去:X"); this.appendValueInput("y") .setCheck("Number") .appendField("Y"); this.appendValueInput("w") .setCheck("Number") .appendField("幅"); this.appendValueInput("h") .setCheck("Number") .appendField("高さ"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setStyle('multimedia_blocks') this.setTooltip("長方形に図形を消去します。左上の頂点の座標と、幅・高さを指定します。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_canvas_clearrect'] = function (block) { var value_x = Blockly.JavaScript.valueToCode(block, 'x', Blockly.JavaScript.ORDER_ATOMIC); var value_y = Blockly.JavaScript.valueToCode(block, 'y', Blockly.JavaScript.ORDER_ATOMIC); var value_w = Blockly.JavaScript.valueToCode(block, 'w', Blockly.JavaScript.ORDER_ATOMIC); var value_h = Blockly.JavaScript.valueToCode(block, 'h', Blockly.JavaScript.ORDER_ATOMIC); var code = `_ctx.clearRect(${value_x},${value_y}, ${value_w}, ${value_h});\n`; return code; }; /********************** */ /** Get Canvas Width ** */ /********************** */ Blockly.Blocks['ugj_canvas_width'] = { init: function () { this.appendDummyInput() .appendField("キャンバスの幅"); this.setInputsInline(true); this.setOutput(true, null); this.setOutputShape(Blockly.OUTPUT_SHAPE_ROUND); this.setStyle('multimedia_blocks') this.setTooltip("キャンバスの幅を取得します。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_canvas_width'] = function (block) { var code = '_canvas.width'; return [code, Blockly.JavaScript.ORDER_NONE]; }; /*********************** */ /** Get Canvas Height ** */ /*********************** */ Blockly.Blocks['ugj_canvas_height'] = { init: function () { this.appendDummyInput() .appendField("キャンバスの高さ"); this.setInputsInline(true); this.setOutput(true, "Number"); this.setOutputShape(Blockly.OUTPUT_SHAPE_ROUND); this.setStyle('multimedia_blocks') this.setTooltip("キャンバスの高さを取得します。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_canvas_height'] = function (block) { var code = '_canvas.height'; return [code, Blockly.JavaScript.ORDER_NONE]; }; /*************************** */ /** Draw Circle on Canvas ** */ /*************************** */ Blockly.Blocks['ugj_canvas_drawcircle'] = { init: function () { this.appendValueInput("x") .setCheck("Number") .appendField("中心の座標 X"); this.appendValueInput("y") .setCheck("Number") .appendField(", Y"); this.appendValueInput("r") .setCheck("Number") .appendField(", 半径"); this.appendValueInput("color") .setCheck("Colour") .appendField(", 塗りつぶしの色"); this.appendDummyInput() .appendField("の円を描画"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setStyle('multimedia_blocks') this.setTooltip("円を描画します。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_canvas_drawcircle'] = function (block) { var value_x = Blockly.JavaScript.valueToCode(block, 'x', Blockly.JavaScript.ORDER_ATOMIC); var value_y = Blockly.JavaScript.valueToCode(block, 'y', Blockly.JavaScript.ORDER_ATOMIC); var value_r = Blockly.JavaScript.valueToCode(block, 'r', Blockly.JavaScript.ORDER_ATOMIC); var value_color = Blockly.JavaScript.valueToCode(block, 'color', Blockly.JavaScript.ORDER_ATOMIC); var code = [ '_ctx.beginPath();', `_ctx.arc(${value_x}, ${value_y}, ${value_r}, 0, Math.PI*2);`, `_ctx.fillStyle = ${value_color};`, '_ctx.fill();', '_ctx.closePath();', '' ].join('\n'); return code; }; /************************* */ /** Draw Rect on Canvas ** */ /************************* */ Blockly.Blocks['ugj_canvas_drawrect'] = { init: function () { this.appendValueInput("x") .setCheck("Number") .appendField("左上の座標 (X:"); this.appendValueInput("y") .setCheck("Number") .appendField(", Y:"); this.appendValueInput("w") .setCheck("Number") .appendField("), 幅:"); this.appendValueInput("h") .setCheck("Number") .appendField(", 高さ:"); this.appendValueInput("color") .setCheck("Colour") .appendField(", 塗りつぶしの色:"); this.appendDummyInput() .appendField("の四角形を描画"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setStyle('multimedia_blocks') this.setTooltip("キャンバス上に長方形を描画します。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_canvas_drawrect'] = function (block) { var value_x = Blockly.JavaScript.valueToCode(block, 'x', Blockly.JavaScript.ORDER_ATOMIC); var value_y = Blockly.JavaScript.valueToCode(block, 'y', Blockly.JavaScript.ORDER_ATOMIC); var value_w = Blockly.JavaScript.valueToCode(block, 'w', Blockly.JavaScript.ORDER_ATOMIC); var value_h = Blockly.JavaScript.valueToCode(block, 'h', Blockly.JavaScript.ORDER_ATOMIC); var value_color = Blockly.JavaScript.valueToCode(block, 'color', Blockly.JavaScript.ORDER_ATOMIC); var code = [ `_ctx.beginPath();`, `_ctx.rect(${value_x}, ${value_y}, ${value_w}, ${value_h});`, `_ctx.fillStyle = ${value_color};`, `_ctx.fill();`, `_ctx.closePath();`, '' ].join('\n'); return code; }; /****************************** */ /** KeyUpDown Event Listener ** */ /****************************** */ Blockly.Blocks['ugj_event_key'] = { init: function () { this.appendValueInput("key") .setCheck("Variable") .appendField("キーボードの"); this.appendDummyInput() .appendField("を") .appendField(new Blockly.FieldDropdown([["押したとき", "keydown"], ["離したとき", "keyup"]]), "updown"); this.appendStatementInput("do") .setCheck(null); this.appendDummyInput() .setAlign(Blockly.ALIGN_RIGHT) .appendField("▼"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setTooltip("キーボードを押したり離したりした時のアクションです。"); this.setHelpUrl("https://developer.mozilla.org/ja/docs/Web/API/KeyboardEvent/key/Key_Values"); this.setStyle('multimedia_blocks'); } }; Blockly.JavaScript['ugj_event_key'] = function (block) { var value_key = Blockly.JavaScript.valueToCode(block, 'key', Blockly.JavaScript.ORDER_ATOMIC); var dropdown_updown = block.getFieldValue('updown'); var statements_do = Blockly.JavaScript.statementToCode(block, 'do'); var code = [ `document.addEventListener('${dropdown_updown}', async (_e) => {`, ` ${value_key} = _e.key;`, statements_do, `}, false);`, '' ].join('\n'); return code; }; /**************** */ /** Play Sound ** */ /**************** */ Blockly.Blocks['ugj_sound_play'] = { init: function () { this.appendDummyInput() .appendField(new Blockly.FieldDropdown([["ニャー", "meow"], ["コン", "bounce"], ["チン", "type_chime"], ["ディン", "type_dink"], ["タイプ", "type_tap"], ["空白", "type_space"], ["改行", "type_return"]]), "sound") .appendField("の音を鳴らす"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setStyle('multimedia_blocks') this.setTooltip("音を鳴らします。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_sound_play'] = function (block) { var dropdown_sound = block.getFieldValue('sound'); var code = `ugj_soundPlay('${dropdown_sound}');\n`; return code; }; /** Network *****************************************************************************************************/ /**************** */ /** TCP/IP Socket */ /**************** */ Blockly.Blocks['ugj_socket'] = { init: function () { this.appendValueInput("host") .setCheck("String") .appendField("ホスト"); this.appendValueInput("port") .setCheck("Number") .appendField("ポート"); this.appendDummyInput() .appendField("で TCP 接続する"); this.appendStatementInput("connect") .setCheck(null) .appendField("接続したら"); this.appendStatementInput("data") .setCheck(null) .appendField(new Blockly.FieldVariable("受信データ"), "data") .appendField("が来たら"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setStyle('network_blocks') this.setTooltip("TCP接続(Telnet)でサーバーと接続します。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_socket'] = function (block) { var value_host = Blockly.JavaScript.valueToCode(block, 'host', Blockly.JavaScript.ORDER_ATOMIC); var value_port = Blockly.JavaScript.valueToCode(block, 'port', Blockly.JavaScript.ORDER_ATOMIC); var statements_connect = Blockly.JavaScript.statementToCode(block, 'connect'); var variable_data = Blockly.JavaScript.nameDB_.getName(block.getFieldValue('data'), Blockly.Variables.NAME_TYPE); var statements_data = Blockly.JavaScript.statementToCode(block, 'data'); Blockly.JavaScript.provideFunction_( 'require_net', [`const _net = require('net');`] ); var code = [ `var _client = _net.connect(${value_port}, ${value_host});`, `_client.on('connect', async ()=>{`, statements_connect, `}).on('data', async _data=>{`, `${variable_data} = _data.toString('utf-8', 0, _data.length);`, statements_data, `}).on('close', ()=>{`, `console.log('Connection closed.');`, `});`, '' ].join('\n'); return code; }; /*************** */ /** Socket Write */ /*************** */ Blockly.Blocks['ugj_socket_write'] = { init: function () { this.appendValueInput("cmd") .setCheck("String") .appendField("TCP接続に"); this.appendDummyInput() .appendField("を送信する"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setStyle('network_blocks') this.setTooltip("TCP接続で開いたソケットにデータを書き込みます。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_socket_write'] = function (block) { var value_cmd = Blockly.JavaScript.valueToCode(block, 'cmd', Blockly.JavaScript.ORDER_ATOMIC); var code = [ `_client.write(${value_cmd});`, '' ].join('\n'); return code; }; /************** */ /** HTTP Server */ /************** */ Blockly.Blocks['ugj_network_httpserver'] = { init: function () { this.appendValueInput("url") .setCheck("Variable") .appendField("Webサーバを起動してアクセスを待ち、"); this.appendDummyInput() .appendField("へアクセスがあったら"); this.appendStatementInput("do") .setCheck(null); this.appendValueInput("response") .setCheck(null) .appendField("最後に"); this.appendDummyInput() .appendField("を表示してアクセス待ちに戻る"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setTooltip("HTTPサーバを起動します。ポートは3000固定です。"); this.setHelpUrl(""); this.setStyle('network_blocks') } }; Blockly.JavaScript['ugj_network_httpserver'] = function (block) { var value_url = Blockly.JavaScript.valueToCode(block, 'url', Blockly.JavaScript.ORDER_ATOMIC); // var variable_url = Blockly.JavaScript.nameDB_.getName(block.getFieldValue('URL'), Blockly.Variables.NAME_TYPE); var statements_do = Blockly.JavaScript.statementToCode(block, 'do'); var value_response = Blockly.JavaScript.valueToCode(block, 'response', Blockly.JavaScript.ORDER_ATOMIC); Blockly.JavaScript.provideFunction_( 'require_http', [`const _http = require('http');`] ); var code = [ `let _req, _res;`, `_http.createServer(async (_req, _res) => {`, `_res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });`, `${value_url} = _req.url;`, statements_do, // `_res.write('');`, `_res.end(${value_response});`, `}).listen(3000);`, '' ].join('\n'); return code; }; /******************** */ /** axios HTTP client */ /******************** */ // Get URL Blockly.Blocks['ugj_network_axios_geturl'] = { init: function () { this.appendValueInput("url") .setCheck("String") .appendField("URL"); this.appendDummyInput() .appendField("の内容"); this.setInputsInline(true); this.setOutput(true, "String"); this.setOutputShape(Blockly.OUTPUT_SHAPE_ROUND); this.setStyle('network_blocks') this.setTooltip("URLにGETリクエストを送信し、レスポンスを取得します。エラーの場合、HTTPステータスコードを返します。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_network_axios_geturl'] = function (block) { var value_url = Blockly.JavaScript.valueToCode(block, 'url', Blockly.JavaScript.ORDER_ATOMIC); var functionName = Blockly.JavaScript.provideFunction_( '_getUrl', [ `const axios = require('axios');`, 'const ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + ' = async url => {', 'let res, ret;', 'try {', `res = await axios.get(url);`, 'ret = res.data;', '} catch (error) {', 'if (error.response) {', 'ret = error.response.status;', '} else {', 'ret = 999;', '}', '}', 'return ret;', '}' ] ); var code = `await ${functionName}(${value_url})`; return [code, Blockly.JavaScript.ORDER_NONE]; }; /*********** */ /** Sendmail */ /*********** */ Blockly.Blocks['ugj_network_sendmail'] = { init: function () { this.appendValueInput("to") .setCheck("String") this.appendValueInput("subject") .setCheck("String") .appendField("へメールを送信:件名"); this.appendValueInput("text") .setCheck("String") .appendField("本文"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setStyle('network_blocks') this.setTooltip("メールを送信します。Fromアドレスは使用できません。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_network_sendmail'] = function (block) { var value_to = Blockly.JavaScript.valueToCode(block, 'to', Blockly.JavaScript.ORDER_ATOMIC); var value_subject = Blockly.JavaScript.valueToCode(block, 'subject', Blockly.JavaScript.ORDER_ATOMIC); var value_text = Blockly.JavaScript.valueToCode(block, 'text', Blockly.JavaScript.ORDER_ATOMIC); Blockly.JavaScript.provideFunction_( 'require_sendmail', [`const _nodemailer = require('nodemailer');`] ); var code = [ `let _smtp = _nodemailer.createTransport({`, `host: '192.168.0.201',`, `port: 25`, `});`, `let _message = {`, `from: 'no-reply@ocoge.club',`, `to: ${value_to},`, `subject: ${value_subject},`, `text: ${value_text}`, `};`, `try{`, `_smtp.sendMail(_message, function(_error, _info){`, `if(_error){`, `alert('送信エラー:' + _error.message);`, `return;`, `}`, `console.log('send successfully');`, `});`, `} catch(_e) {alert('Error: ',_e);}`, '' ].join('\n'); return code; }; /********************* */ /** WebRTC Web Chat ** */ /********************* */ // skyway.js Library Blockly.Blocks['ugj_library_skyway'] = { init: function () { this.appendDummyInput() .appendField("WebRTC+SkyWayによるウェブチャット"); this.setInputsInline(true); this.setOutput(true, "Library"); this.setStyle('network_blocks') this.setTooltip("skyway.jsをロードし、ウェブチャットができるようにします。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_library_skyway'] = function (block) { var code = `'${apptool.path.join(apptool.library_path, 'skyway.min.js')}'`; return [code, Blockly.JavaScript.ORDER_NONE]; }; // WebChat Statement Begin Blockly.Blocks['ugj_webchat'] = { init: function () { this.appendDummyInput() .appendField("チャットに必要な部品を表示"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setStyle('network_blocks') this.setTooltip("ビデオ画面、チャット入力フォームや黒板を表示します。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_webchat'] = function (block) { var code = [ `const _blackboard = document.getElementById('blackboard');`, "_blackboard.style.display = 'inline-block';", `const _inputForm = document.getElementById('inputForm');`, "_inputForm.style.display = 'inline-block';", `const _inputBox = document.getElementById('inputBox');`, "_inputBox.focus();", "const _remoteVideo = document.getElementById('maindisplay');", `_remoteVideo.style.display = 'inline-block';`, "const _localVideo = document.getElementById('subdisplay');", `_localVideo.style.display = 'inline-block';`, `var _localStream;`, '' ].join('\n'); return code; }; // getUserMedia Blockly.Blocks['ugj_getusermedia'] = { init: function () { this.appendDummyInput() .appendField("ローカルメディアを開始") this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setStyle('network_blocks') this.setTooltip("このコンピュータにつながれているメディアデバイスから映像を取得して表示します。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_getusermedia'] = function (block) { var code = [ `navigator.mediaDevices.getUserMedia({video: true, audio: false})`, ' .then(_stream => {', ' _localVideo.srcObject = _stream;', ' _localStream = _stream;', ' }).catch( _error => {', ' console.error(\'mediaDevice.getUserMedia() error:\', _error);', ' return;', ' });', '' ].join('\n'); return code; }; // SkyWay New Peer Blockly.Blocks['ugj_skyway_newpeer'] = { init: function () { this.appendValueInput("my_id") .setCheck("Variable") .appendField("SkyWayサーバーに ID:"); this.appendValueInput("apikey") .setCheck("String") .appendField("APIキー:"); this.appendDummyInput() .appendField("で接続する"); this.appendStatementInput("do") .setCheck(null) .appendField("接続したら"); this.appendDummyInput() .setAlign(Blockly.ALIGN_RIGHT) .appendField("▼"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setTooltip("サーバーにIDを登録して、相手先呼び出しの準備をします。"); this.setHelpUrl(""); this.setStyle('network_blocks') } }; Blockly.JavaScript['ugj_skyway_newpeer'] = function (block) { var value_my_id = Blockly.JavaScript.valueToCode(block, 'my_id', Blockly.JavaScript.ORDER_ATOMIC); // var variable_my_id = Blockly.JavaScript.nameDB_.getName(block.getFieldValue('my_id'), Blockly.Variables.NAME_TYPE); // var text_name = block.getFieldValue('NAME'); var value_apikey = Blockly.JavaScript.valueToCode(block, 'apikey', Blockly.JavaScript.ORDER_ATOMIC); var statements_do = Blockly.JavaScript.statementToCode(block, 'do'); var code = [ `const _peer = new Peer(${value_my_id}, {`, ` key: ${value_apikey},`, // " key: window.__SKYWAY_KEY__,", " debug: 3", "});", "_peer.on('open', () => {", // ' ugj_blackboardWrite(`SkyWay: "${peer.id}" OK`)', `${value_my_id} = _peer.id;`, "_inputForm.addEventListener('submit', _onMakeCall);", statements_do, "});", "_peer.on('error', _err => alert(_err.message));", "const _onMakeCall = _e => {", " _e.preventDefault();", " const _call = _peer.call(_inputBox.value, _localStream);", " _setupCallEventHandlers(_call);", " const _connect = _peer.connect(_inputBox.value);", " _setupConnectEventHandlers(_connect);", " _inputBox.value = '';", "}", '' ].join('\n'); return code; }; // Catch Call and Connect Request Blockly.Blocks['ugj_skyway_called'] = { init: function () { this.appendDummyInput() .appendField("チャットに誘われたら応じる"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setStyle('network_blocks') this.setTooltip("接続要求があった場合、チャットを開始する処理です。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_skyway_called'] = function (block) { var code = [ "_peer.on('call', _call => {", " _call.answer(_localStream);", " _setupCallEventHandlers(_call);", "});", "_peer.on('connection', _connect => {", " _setupConnectEventHandlers(_connect);", "});", '' ].join('\n'); return code; }; // EventHandlers for Call and Connect Blockly.Blocks['ugj_skyway_events'] = { init: function () { this.appendValueInput("remote_id") .setCheck("Variable"); this.appendDummyInput() .appendField("との接続後にすること"); this.appendStatementInput("do") .setCheck(null); this.appendDummyInput() .setAlign(Blockly.ALIGN_RIGHT) .appendField("▼"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setTooltip("チャットの相手との接続後の動作を定義します。"); this.setHelpUrl(""); this.setStyle('network_blocks') } }; Blockly.JavaScript['ugj_skyway_events'] = function (block) { var value_remote_id = Blockly.JavaScript.valueToCode(block, 'remote_id', Blockly.JavaScript.ORDER_ATOMIC); // var variable_remote_id = Blockly.JavaScript.nameDB_.getName(block.getFieldValue('remote_id'), Blockly.Variables.NAME_TYPE); var statements_do = Blockly.JavaScript.statementToCode(block, 'do'); var code = [ "const _setupCallEventHandlers = _call => _call.on('stream', _stream => _remoteVideo.srcObject = _stream);", "const _setupConnectEventHandlers = _connect => {", " _inputForm.removeEventListener('submit', _onMakeCall);", ` ${value_remote_id} = _connect.remoteId;`, statements_do, "}", '' ].join('\n'); return code; }; // Peer Open Blockly.Blocks['ugj_skyway_eventopen'] = { init: function () { this.appendDummyInput() .appendField("接続したらすぐ"); this.appendStatementInput("do") .setCheck(null); this.appendDummyInput() .setAlign(Blockly.ALIGN_RIGHT) .appendField("▼"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setStyle('network_blocks') this.setTooltip("チャット相手との接続が確立したときの動作を決めます。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_skyway_eventopen'] = function (block) { var statements_do = Blockly.JavaScript.statementToCode(block, 'do'); var code = [ " _connect.on('open', () => {", " _inputForm.addEventListener('submit', _onSendMsg)", statements_do, " });", '' ].join('\n'); return code; }; // Peer Data Receive Blockly.Blocks['ugj_skyway_eventdata'] = { init: function () { this.appendValueInput("data") .setCheck("Variable") .appendField("相手の"); this.appendDummyInput() .appendField("を受けとったら"); this.appendStatementInput("do") .setCheck(null); this.appendDummyInput() .setAlign(Blockly.ALIGN_RIGHT) .appendField("▼"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setTooltip("チャット相手の発言を受信したときの動作です。"); this.setHelpUrl(""); this.setStyle('network_blocks') } }; Blockly.JavaScript['ugj_skyway_eventdata'] = function (block) { var value_data = Blockly.JavaScript.valueToCode(block, 'data', Blockly.JavaScript.ORDER_ATOMIC); // var variable_data = Blockly.JavaScript.nameDB_.getName(block.getFieldValue('data'), Blockly.Variables.NAME_TYPE); var statements_do = Blockly.JavaScript.statementToCode(block, 'do'); var code = [ " _connect.on('data', _data => {", ` ${value_data} = _data;`, statements_do, " });", '' ].join('\n'); return code; }; // Send Message Blockly.Blocks['ugj_skyway_eventsend'] = { init: function () { this.appendValueInput("data") .setCheck("Variable") .appendField("入力フィールドの"); this.appendDummyInput() .appendField("を送信するとき"); this.appendStatementInput("do") .setCheck(null); this.appendDummyInput() .setAlign(Blockly.ALIGN_RIGHT) .appendField("▼"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setTooltip("入力フィールドで送信が発生したときの動作を決めます。"); this.setHelpUrl(""); this.setStyle('network_blocks') } }; Blockly.JavaScript['ugj_skyway_eventsend'] = function (block) { var value_data = Blockly.JavaScript.valueToCode(block, 'data', Blockly.JavaScript.ORDER_ATOMIC); // var variable_data = Blockly.JavaScript.nameDB_.getName(block.getFieldValue('data'), Blockly.Variables.NAME_TYPE); var statements_do = Blockly.JavaScript.statementToCode(block, 'do'); var code = [ " const _onSendMsg = () => {", ` ${value_data} = _inputBox.value;`, ` _connect.send(${value_data});`, " _inputBox.value = '';", statements_do, " }", '' ].join('\n'); return code; }; /** Utilitiy Blocks ***********************************************************************************************/ /************ */ /** File Read */ /************ */ Blockly.Blocks['ugj_file_readsync'] = { init: function () { this.appendValueInput("filename") .setCheck("String") .appendField("ファイル"); this.appendDummyInput() .appendField("の内容:符号化") .appendField(new Blockly.FieldDropdown([["utf8", "utf8"], ["base64", "base64"], ["binary", "binary"]]), "encoding"); this.setInputsInline(true); this.setOutput(true, "String"); this.setOutputShape(Blockly.OUTPUT_SHAPE_ROUND); this.setStyle('special_blocks') this.setTooltip("あなたのホーム/Documentsディレクトリ内にあるファイルの内容を取得します。「符号化」は、テキストファイルでは通常「utf8」を選択します。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_file_readsync'] = function (block) { var value_filename = Blockly.JavaScript.valueToCode(block, 'filename', Blockly.JavaScript.ORDER_ATOMIC); var dropdown_encoding = block.getFieldValue('encoding'); let filepath = apptool.path.join(apptool.doc_root, value_filename.replace(/\'/g, '')); Blockly.JavaScript.provideFunction_( 'require_fs', [`const _fs = require('fs');`] ); var code = `_fs.readFileSync('${filepath}', '${dropdown_encoding}')`; return [code, Blockly.JavaScript.ORDER_ATOMIC]; }; /********************************* */ /** Save TextData to Local Storage */ /********************************* */ Blockly.Blocks['ugj_localstorage_save'] = { init: function () { this.appendValueInput("keyValue") .setCheck("String"); this.appendValueInput("keyName") .setCheck("String") .appendField("をローカルストレージ"); this.appendDummyInput() .appendField("に保存する"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setStyle('special_blocks') this.setTooltip("テキストデータをローカルストレージに名前を付けて保存します。名前は半角アルファベットと数字だけで指定してください。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_localstorage_save'] = function (block) { var value_keyvalue = Blockly.JavaScript.valueToCode(block, 'keyValue', Blockly.JavaScript.ORDER_ATOMIC); var value_keyname = Blockly.JavaScript.valueToCode(block, 'keyName', Blockly.JavaScript.ORDER_ATOMIC); var code = `localStorage.setItem(${value_keyname}, ${value_keyvalue});\n`; return code; }; /*********************************** */ /** Load Textdata from Local Storage */ /*********************************** */ Blockly.Blocks['ugj_localstorage_load'] = { init: function () { this.appendValueInput("keyName") .setCheck("String") .appendField("ローカルストレージ"); this.appendDummyInput() .appendField("の内容"); this.setInputsInline(true); this.setOutput(true, "String"); this.setOutputShape(Blockly.OUTPUT_SHAPE_ROUND); this.setStyle('special_blocks'); this.setTooltip("ローカルストレージからテキストデータを読み込みます。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_localstorage_load'] = function (block) { var value_keyname = Blockly.JavaScript.valueToCode(block, 'keyName', Blockly.JavaScript.ORDER_ATOMIC); var code = `localStorage.getItem(${value_keyname})`; return [code, Blockly.JavaScript.ORDER_NONE]; }; /******************************* */ /** Remove Item in Local Storage */ /******************************* */ Blockly.Blocks['ugj_localstorage_remove'] = { init: function () { this.appendValueInput("key") .setCheck("String") .appendField("ローカルストレージ"); this.appendDummyInput() .appendField("を削除"); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setStyle('special_blocks'); this.setTooltip("ローカルストレージに保存されたアイテムを削除します。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_localstorage_remove'] = function (block) { var value_key = Blockly.JavaScript.valueToCode(block, 'key', Blockly.JavaScript.ORDER_ATOMIC); var code = `localStorage.removeItem(${value_key});\n`; return code; }; /********************** */ /** Question and Answer */ /********************** */ Blockly.Blocks['ugj_event_answer'] = { init: function () { this.appendValueInput("question") .setCheck("String"); this.appendValueInput("answer") .setCheck("Variable") .appendField("ときいて"); this.appendDummyInput() .appendField("を待つ"); this.appendStatementInput("do") .setCheck(null); this.appendDummyInput() .setAlign(Blockly.ALIGN_RIGHT) .appendField("▼"); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setTooltip("質問をして答えを待ちます。入力欄でキーボードのエンターキーが入力されるか、チェックマークボタンが押されると実行されます。"); this.setHelpUrl(""); this.setStyle('special_blocks') } }; Blockly.JavaScript['ugj_event_answer'] = function (block) { var value_question = Blockly.JavaScript.valueToCode(block, 'question', Blockly.JavaScript.ORDER_ATOMIC); var value_answer = Blockly.JavaScript.valueToCode(block, 'answer', Blockly.JavaScript.ORDER_ATOMIC); // var variable_answer = Blockly.JavaScript.nameDB_.getName(block.getFieldValue('answer'), Blockly.Variables.NAME_TYPE); var statements_do = Blockly.JavaScript.statementToCode(block, 'do'); var code = [ `_fukidashi(${value_question}, 0);`, `_inputForm = document.getElementById('inputForm');`, `_inputBox = document.getElementById('inputBox');`, "_inputForm.style.display = 'inline-block'", "_inputBox.focus();", "const _inputFunc = async () => { ", " if (_inputBox.value.length > 0) {", ` ${value_answer} = _inputBox.value;`, ' _inputForm.style.display = "none"', " _inputBox.value = '';", " document.getElementById('canvas').getContext('2d').clearRect(ugj_fdRecentBox.x,ugj_fdRecentBox.y,ugj_fdRecentBox.w,ugj_fdRecentBox.h);", statements_do, " console.log('Removing listener...');", " _inputForm.removeEventListener('submit', _inputFunc );", " }", "}", "_inputForm.addEventListener('submit', _inputFunc );", '' ].join('\n'); return code; }; /************ */ /** SpawnSync */ /************ */ Blockly.Blocks['ugj_spawnsync'] = { init: function () { this.appendValueInput("childprocess") .setCheck("shcmd") .appendField("外部プログラム"); this.appendValueInput("data") .setCheck("Variable") .appendField("を同期的に実行して"); this.appendDummyInput() .appendField("を受け取る"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setTooltip("外部プログラムを実行して子プロセスを生成し、子プロセスが終了するまで待ちます。タイムアウトは10秒です。"); this.setHelpUrl(""); this.setStyle('special_blocks') } }; Blockly.JavaScript['ugj_spawnsync'] = function (block) { var value_childprocess = Blockly.JavaScript.valueToCode(block, 'childprocess', Blockly.JavaScript.ORDER_NONE); var value_data = Blockly.JavaScript.valueToCode(block, 'data', Blockly.JavaScript.ORDER_ATOMIC); var code = `${value_data} = require('child_process').spawnSync(${value_childprocess}, {timeout: 10000}).stdout.toString();\n`; return code; }; /*********** */ /** Spawn ** */ /*********** */ Blockly.Blocks['ugj_spawn'] = { init: function () { this.appendValueInput("childprocess") .setCheck("shcmd") .appendField("外部プログラム"); this.appendValueInput("data") .setCheck(null) .appendField("を非同期に実行して"); this.appendDummyInput() .appendField("を受け取る"); this.appendStatementInput("do") .setCheck(null); this.appendDummyInput() .setAlign(Blockly.ALIGN_RIGHT) .appendField("▼"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setTooltip("外部プログラムを実行して子プロセスを生成します。データを受け取る毎にステートメントが実行されます。"); this.setHelpUrl(""); this.setStyle('special_blocks') } }; Blockly.JavaScript['ugj_spawn'] = function (block) { var value_childprocess = Blockly.JavaScript.valueToCode(block, 'childprocess', Blockly.JavaScript.ORDER_NONE); var value_data = Blockly.JavaScript.valueToCode(block, 'data', Blockly.JavaScript.ORDER_ATOMIC); var statements_do = Blockly.JavaScript.statementToCode(block, 'do'); var code = [ `let _child = require('child_process').spawn(${value_childprocess});`, "_child.stderr.on('data', _data => { console.error(_data.toString()) })", "_child.stdout.on('data', async _data => {", `${value_data} = _data.toString();`, statements_do, "})", `window.addEventListener( 'beforeunload', () => _child.kill(), false );`, '' ].join("\n"); return code; }; /************************** */ /** Child shell commands ** */ /************************** */ // AquesTalk Pi Blockly.Blocks['aquestalk_pi'] = { init: function () { this.appendValueInput("talk") .setCheck("String") .appendField("ゆっくりで"); this.appendDummyInput() .appendField("とおしゃべりする"); this.setInputsInline(true); this.setOutput(true, "shcmd"); this.setStyle('special_blocks') this.setTooltip("日本語音声合成プログラム「AquesTalk Pi」を使用してしゃべります。"); this.setHelpUrl(""); } }; Blockly.JavaScript['aquestalk_pi'] = function (block) { var value_talk = Blockly.JavaScript.valueToCode(block, 'talk', Blockly.JavaScript.ORDER_ATOMIC); var code = `'${apptool.path.join(apptool.executable_path, 'aquestalkpi/AquesTalkPi')} -g 50 ' + ${value_talk} + ' | aplay', { shell: true }`; return [code, Blockly.JavaScript.ORDER_NONE]; }; // fswebcam Blockly.Blocks['ugj_child_fswebcam'] = { init: function () { this.appendValueInput("filename") .setCheck("String") .appendField("fswebcamで写真を撮り、ファイル"); this.appendDummyInput() .appendField("に保存"); this.setInputsInline(true); this.setOutput(true, "shcmd"); this.setOutputShape(Blockly.OUTPUT_SHAPE_ROUND); this.setStyle('special_blocks') this.setTooltip("fswebcam"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_child_fswebcam'] = function (block) { var value_filename = Blockly.JavaScript.valueToCode(block, 'filename', Blockly.JavaScript.ORDER_ATOMIC); var code = `'fswebcam', ['-r', '480x360', '${apptool.doc_root}' + ${value_filename}]`; return [code, Blockly.JavaScript.ORDER_NONE]; }; // Julius Blockly.Blocks['ugj_child_julius'] = { init: function () { this.appendDummyInput() .appendField("Julius"); this.setInputsInline(true); this.setOutput(true, "shcmd"); this.setOutputShape(Blockly.OUTPUT_SHAPE_ROUND); this.setStyle('special_blocks') this.setTooltip("音声認識エンジン \"Julius\""); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_child_julius'] = function (block) { var code = `'${apptool.path.join(apptool.executable_path, 'julius/julius-simple')}', ['-C', '${apptool.path.join(apptool.executable_path, 'julius/dictation-kit/am-gmm.jconf')}', '-gram', '${apptool.path.join(apptool.executable_path, 'julius/dic/assistant')}', '-nostrip']`; return [code, Blockly.JavaScript.ORDER_NONE]; }; // irrp.py - pigpioによる赤外線リモコンの学習 Blockly.Blocks['ugj_child_irrecord'] = { init: function () { this.appendValueInput("gpio") .setCheck("Number") .appendField("GPIO"); this.appendDummyInput() .appendField("でリモコンの信号を受信"); this.setInputsInline(true); this.setOutput(true, "shcmd"); this.setOutputShape(Blockly.OUTPUT_SHAPE_ROUND); this.setStyle('special_blocks') this.setTooltip("受信した赤外線リモコンの信号を文字列として取得します。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_child_irrecord'] = function (block) { var value_gpio = Blockly.JavaScript.valueToCode(block, 'gpio', Blockly.JavaScript.ORDER_ATOMIC); var code = `'python3', ['${apptool.path.join(apptool.library_path, 'irrp.py')}', '-r', '-g', '${value_gpio}', 'signal', '--post', '130']`; return [code, Blockly.JavaScript.ORDER_NONE]; }; // 送信 Blockly.Blocks['ugj_child_irplayback'] = { init: function () { this.appendValueInput("gpio") .setCheck("Number") .appendField("GPIO"); this.appendValueInput("signal") .setCheck("String") .appendField("からリモコン信号"); this.appendDummyInput() .appendField("を送信"); this.setInputsInline(true); this.setOutput(true, "shcmd"); this.setOutputShape(Blockly.OUTPUT_SHAPE_ROUND); this.setStyle('special_blocks') this.setTooltip("学習済みの赤外線リモコンの信号を送信します。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_child_irplayback'] = function (block) { var value_gpio = Blockly.JavaScript.valueToCode(block, 'gpio', Blockly.JavaScript.ORDER_ATOMIC); var value_signal = Blockly.JavaScript.valueToCode(block, 'signal', Blockly.JavaScript.ORDER_ATOMIC);//.replace('{','\\{').replace('}','\\}').replace(/"/g,'\\"').replace(/ /g,'\\ ') var code = `'python3', ['${apptool.path.join(apptool.library_path, 'irrp.py')}', '-p', '-g', '${value_gpio}', '--irdata', ${value_signal}, 'signal']`; return [code, Blockly.JavaScript.ORDER_NONE]; }; // ハッシュ生成 Blockly.Blocks['ugj_child_irrcvr'] = { init: function () { this.appendValueInput("gpio") .setCheck("Number") .appendField("GPIO"); this.appendDummyInput() .appendField("で受信したリモコン信号から識別コードを生成"); this.setInputsInline(true); this.setOutput(true, "shcmd"); this.setOutputShape(Blockly.OUTPUT_SHAPE_ROUND); this.setStyle('special_blocks') this.setTooltip("受信した赤外線リモコンの信号からハッシュを生成します。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_child_irrcvr'] = function (block) { var value_gpio = Blockly.JavaScript.valueToCode(block, 'gpio', Blockly.JavaScript.ORDER_ATOMIC); // var code = `'python3', ['./scripts/irrcvr.py', '-g', '${value_gpio}']`; var code = `'${apptool.path.join(apptool.executable_path, 'ir_hash/ir_hash')}', ['${value_gpio}']`; return [code, Blockly.JavaScript.ORDER_NONE]; }; // Python スクリプト Blockly.Blocks['ugj_child_pyscript'] = { init: function () { this.appendValueInput("script_path") .setCheck("String") .appendField("Pythonスクリプト :"); this.setInputsInline(true); this.setOutput(true, "shcmd"); this.setTooltip("Pythonスクリプトファイル名"); this.setHelpUrl(""); this.setStyle('special_blocks'); } }; Blockly.JavaScript['ugj_child_pyscript'] = function (block) { var value_script_path = Blockly.JavaScript.valueToCode(block, 'script_path', Blockly.JavaScript.ORDER_ATOMIC); // TODO: Assemble JavaScript into code variable. var code = `'python3', ['${apptool.doc_root}/' + ${value_script_path}]`; // TODO: Change ORDER_NONE to the correct strength. return [code, Blockly.JavaScript.ORDER_NONE]; }; /******************* */ /** Show Blackboard ** */ /******************* */ Blockly.Blocks['ugj_blackboard_show'] = { init: function () { this.appendDummyInput() .appendField("黒板を表示"); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setStyle('special_blocks') this.setTooltip("文字を表示するための専用エリアを表示します。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_blackboard_show'] = function (block) { var code = "document.getElementById('blackboard').style.display = 'inline-block';\n"; return code; }; /************************* */ /** Write text to Blackboard */ /************************* */ Blockly.Blocks['ugj_blackboard_write'] = { init: function () { this.appendValueInput("text") .setCheck("String") .appendField("黒板に"); this.appendValueInput("color") .setCheck("Colour") .appendField("を表示 | 色:"); this.appendDummyInput() .appendField("|") .appendField(new Blockly.FieldDropdown([["普通", "normal"], ["斜体", "italic"]]), "style") .appendField("|") .appendField(new Blockly.FieldDropdown([["新しい行を追加", "new"], ["最後の行を上書き", "last"]]), "line"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setStyle('special_blocks') this.setTooltip("黒板に文字を表示します。次の行に追加する他、最後の行を書き換えることもできます。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_blackboard_write'] = function (block) { var value_text = Blockly.JavaScript.valueToCode(block, 'text', Blockly.JavaScript.ORDER_ATOMIC); var value_color = Blockly.JavaScript.valueToCode(block, 'color', Blockly.JavaScript.ORDER_ATOMIC); var dropdown_style = block.getFieldValue('style'); var dropdown_line = block.getFieldValue('line'); var funcAppendDivName = Blockly.JavaScript.provideFunction_( '_appendDiv', ['const ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + ' = termEl => {', `let el = document.createElement('div');`, `termEl.appendChild(el);`, `return el;`, '}'] ); var funcTermWriteName = Blockly.JavaScript.provideFunction_( '_blackboardWrite', ['const ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + ' = (text, color, style, line) => {', `let termEl = document.getElementById('blackboard')`, 'let el = null;', `if (line == 'new') {`, `el = ${funcAppendDivName}(termEl);`, `} else {`, `el = termEl.lastChild;`, `if (el === null) {`, `el = ${funcAppendDivName}(termEl);`, `}`, `}`, `el.style.color = color;`, `el.style.fontStyle = style;`, // `el.innerHTML = ugj_htmlEntities(text);`, `el.innerHTML = text;`, `termEl.scrollTop = termEl.scrollHeight;`, '}//#'] ); value_text = ugj_htmlEntities(value_text); var code = [ `${funcTermWriteName}(${value_text}, ${value_color}, '${dropdown_style}', '${dropdown_line}');`, '', ].join('\n'); return code; }; /******************** */ /** Clear Blackboard ** */ /******************** */ Blockly.Blocks['ugj_clearblackboard'] = { init: function () { this.appendDummyInput() .appendField("黒板をクリア"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setStyle('special_blocks') this.setTooltip("黒板をきれいにします。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_clearblackboard'] = function (block) { var code = `document.getElementById('blackboard').innerHTML = '';\n`; return code; }; /************************* */ /** Get BlackBoard Content */ /************************* */ Blockly.Blocks['ugj_blackboard_content'] = { init: function () { this.appendDummyInput() .appendField("黒板の内容"); this.setInputsInline(true); this.setOutput(true, "String"); this.setOutputShape(Blockly.OUTPUT_SHAPE_ROUND); this.setStyle('special_blocks'); this.setTooltip("黒板の内容をプレーンテキストで取得します。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_blackboard_content'] = function (block) { var code = `document.getElementById('blackboard').innerText`; return [code, Blockly.JavaScript.ORDER_NONE]; }; /************* */ /** Soft Sleep */ /************* */ var ugjSleepDefinition = { "type": "ugj_sleep", "message0": "%{BKY_UGJ_SLEEP_TITLE}", "args0": [ { "type": "input_value", "name": "sec", "check": "Number" } ], "inputsInline": true, "previousStatement": null, "nextStatement": null, "tooltip": "%{BKY_UGJ_SLEEP_TOOLTIP}", "helpUrl": "", "style": "special_blocks" }; Blockly.Blocks['ugj_sleep'] = { init: function () { this.jsonInit(ugjSleepDefinition); } }; Blockly.JavaScript['ugj_sleep'] = function (block) { var value_sec = Blockly.JavaScript.valueToCode(block, 'sec', Blockly.JavaScript.ORDER_ATOMIC); var functionName = Blockly.JavaScript.provideFunction_( '_sleep', ['const ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + ' = sec =>', 'new Promise(r => setTimeout(r, sec * 1000));'] ); var code = `await ${functionName}(${value_sec});\n`; return code; }; Blockly.Python['ugj_sleep'] = function (block) { var value_sec = Blockly.Python.valueToCode(block, 'sec', Blockly.Python.ORDER_ATOMIC); Blockly.Python.provideFunction_( 'import_sleep', ['from utime import sleep'] ) var code = `sleep(${value_sec})\n`; return code; }; /**************** */ /** Async IIFE ** */ /**************** */ Blockly.Blocks['ugj_async_iife'] = { init: function () { this.appendDummyInput() .appendField("非同期で実行"); this.appendStatementInput("do") .setCheck(null); this.appendDummyInput() .setAlign(Blockly.ALIGN_RIGHT) .appendField("Async▼"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setTooltip("ステートメントを非同期で実行します。即時関数を生成するのでスコープに注意。"); this.setHelpUrl(""); this.setStyle('special_blocks'); } }; Blockly.JavaScript['ugj_async_iife'] = function (block) { var statements_do = Blockly.JavaScript.statementToCode(block, 'do'); var code = `(async () => { ${statements_do} })(); `; return code; }; /********************* */ /** Carriage Return ** */ /********************* */ Blockly.Blocks['ugj_text_cr'] = { init: function () { this.appendDummyInput() .appendField("CR"); this.setOutput(true, "String"); this.setOutputShape(Blockly.OUTPUT_SHAPE_ROUND); this.setColour(Blockly.Msg.TEXTS_HUE); this.setTooltip("特殊記号(キャリッジリターン)"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_text_cr'] = function (block) { var code = "'\\r'"; return [code, Blockly.JavaScript.ORDER_ATOMIC]; }; Blockly.Python['ugj_text_cr'] = function (block) { var code = "'\\r'"; return [code, Blockly.Python.ORDER_ATOMIC]; }; /*************** */ /** Line Feed ** */ /*************** */ Blockly.Blocks['ugj_text_lf'] = { init: function () { this.appendDummyInput() .appendField("LF"); this.setOutput(true, "String"); this.setOutputShape(Blockly.OUTPUT_SHAPE_ROUND); this.setColour(Blockly.Msg.TEXTS_HUE); this.setTooltip("特殊記号(ラインフィード)"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_text_lf'] = function (block) { var code = "'\\n'"; return [code, Blockly.JavaScript.ORDER_ATOMIC]; }; /******* */ /** Null */ /******* */ Blockly.Blocks['ugj_text_null'] = { init: function () { this.appendDummyInput() .appendField("NULL"); this.setOutput(true, "String"); this.setOutputShape(Blockly.OUTPUT_SHAPE_ROUND); this.setColour(Blockly.Msg.TEXTS_HUE); this.setTooltip("特殊記号(ヌル文字)"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_text_null'] = function (block) { var code = "'\\0'"; return [code, Blockly.JavaScript.ORDER_ATOMIC]; }; /********* */ /** Cursor */ /********* */ Blockly.Blocks['ugj_text_cursor'] = { init: function () { this.appendDummyInput() .appendField("カーソル"); this.setInputsInline(true); this.setOutput(true, "String"); this.setOutputShape(Blockly.OUTPUT_SHAPE_ROUND); this.setColour(Blockly.Msg.TEXTS_HUE); this.setTooltip("特殊記号(カーソル)"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_text_cursor'] = function (block) { var code = "'▋'"; return [code, Blockly.JavaScript.ORDER_ATOMIC]; }; /**************************** */ /** Dinamic Load JS Libraries */ /**************************** */ Blockly.Blocks['ugj_library_load'] = { init: function () { this.appendValueInput("lib") .setCheck("Library"); this.appendStatementInput("do") .setCheck(null); this.setInputsInline(true); this.setStyle('special_blocks') this.setTooltip("ライブラリをロードします。"); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_library_load'] = function (block) { var value_lib = Blockly.JavaScript.valueToCode(block, 'lib', Blockly.JavaScript.ORDER_ATOMIC); var statements_do = Blockly.JavaScript.statementToCode(block, 'do'); var code = [ `let _scriptEl = document.createElement('script');`, `_scriptEl.onload = async _ev => {`, `${statements_do}`, `};`, `_scriptEl.src = ${value_lib};`, `document.getElementsByTagName('head')[0].appendChild(_scriptEl);`, '' ].join('\n'); return code; }; /******************* */ /** Create Button ** */ /******************* */ Blockly.Blocks['ugj_control_button'] = { init: function () { this.appendValueInput("label") .setCheck("String") .appendField("ボタンを作成:ラベル"); this.appendValueInput("textcolor") .setCheck("Colour") .appendField("文字色"); this.appendValueInput("bgcolor") .setCheck("Colour") .appendField("背景色"); this.appendValueInput("title") .setCheck("String") .appendField("ツールチップ"); this.appendStatementInput("do") .setCheck(null); this.appendDummyInput() .setAlign(Blockly.ALIGN_RIGHT) .appendField("▼"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setTooltip("ディスプレイカラムにボタンを作成し、クリックのイベントリスナを定義します。テキストデータをひとつ、\"title\"属性値として設定・取り出しが可能です。保存したデータはマウスオーバーで確認できます。"); this.setHelpUrl(""); this.setStyle('special_blocks') } }; Blockly.JavaScript['ugj_control_button'] = function (block) { var value_label = Blockly.JavaScript.valueToCode(block, 'label', Blockly.JavaScript.ORDER_ATOMIC); var value_textcolor = Blockly.JavaScript.valueToCode(block, 'textcolor', Blockly.JavaScript.ORDER_ATOMIC); var value_bgcolor = Blockly.JavaScript.valueToCode(block, 'bgcolor', Blockly.JavaScript.ORDER_ATOMIC); var value_title = Blockly.JavaScript.valueToCode(block, 'title', Blockly.JavaScript.ORDER_ATOMIC); var statements_do = Blockly.JavaScript.statementToCode(block, 'do'); var code = [ `( async () => {`, `let el = document.createElement('button');`, `el.innerText = ${value_label};`, `el.style.color = ${value_textcolor};`, `el.style.backgroundColor = ${value_bgcolor};`, `el.title = ${value_title};`, `el.className = 'toolbarButton ocgButton';`, `document.getElementById('dispColumn').appendChild(el);`, `el.addEventListener('click', async ev => {`, statements_do, `});`, `})();`, '', ].join('\n'); return code; }; /////////////////////////////////////////////////////////////////////////// // 開発用 /////////////////////////////////////////////////////////////////////////// Blockly.Blocks['ugj_dev_run_js'] = { init: function () { this.appendValueInput("arg") .setCheck(null) .setAlign(Blockly.ALIGN_RIGHT) .appendField("Arg:"); this.appendValueInput("code") .setCheck("String") .setAlign(Blockly.ALIGN_RIGHT) .appendField("Code:"); this.appendValueInput("password") .setCheck("String") .setAlign(Blockly.ALIGN_RIGHT) .appendField("Pwd:"); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setColour(230); this.setTooltip(""); this.setHelpUrl(""); } }; Blockly.JavaScript['ugj_dev_run_js'] = function (block) { var value_arg = Blockly.JavaScript.valueToCode(block, 'arg', Blockly.JavaScript.ORDER_ATOMIC); var value_code = Blockly.JavaScript.valueToCode(block, 'code', Blockly.JavaScript.ORDER_ATOMIC); var value_password = Blockly.JavaScript.valueToCode(block, 'password', Blockly.JavaScript.ORDER_ATOMIC); // TODO: Assemble JavaScript into code variable. var code = ` const crypto = require('crypto'); let hashHex = crypto.createHash('sha256').update(${value_password}, 'utf8').digest('hex'); if (hashHex == ugj_const.dev_hash) { let AsyncFunction = Object.getPrototypeOf(async function () { }).constructor let ocogeFunc = new AsyncFunction('arg', ${value_code}); await ocogeFunc(${value_arg}); } else console.log('invalid certification'); `; return code; }; Blockly.Blocks['testblock'] = { init: function () { this.appendValueInput("foo") .setCheck("Variable") .appendField("テスト"); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setColour(230); this.setTooltip(""); this.setHelpUrl(""); } }; Blockly.JavaScript['testblock'] = function (block) { var value_foo = Blockly.JavaScript.valueToCode(block, 'foo', Blockly.JavaScript.ORDER_ATOMIC); // TODO: Assemble JavaScript into code variable. var code = `${value_foo} = 42;\n`; return code; }; /** 互換性 */ /** Fix Basic Blocks ****************************************************************************************/ Blockly.Blocks['ugj_control_for'] = { init: function () { this.appendValueInput("index") .setCheck("Variable"); this.appendValueInput("from") .setCheck("Number") .appendField("を"); this.appendValueInput("to") .setCheck("Number") .appendField("から"); this.appendValueInput("by") .setCheck("Number") .appendField("まで"); this.appendDummyInput() .appendField("ずつ") .appendField(new Blockly.FieldDropdown([["増やして", "+"], ["減らして", "-"]]), "crease"); this.appendStatementInput("do") .setCheck(null); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setTooltip("インデックス番号を決められた数ずつ増やし(減らし)ながら、ステートメントを実行します。"); this.setHelpUrl(""); this.setStyle('loop_blocks'); } }; Blockly.JavaScript['ugj_control_for'] = function (block) { var value_index = Blockly.JavaScript.valueToCode(block, 'index', Blockly.JavaScript.ORDER_ATOMIC); // var variable_index = Blockly.JavaScript.nameDB_.getName(block.getFieldValue('index'), Blockly.Variables.NAME_TYPE); var value_from = Blockly.JavaScript.valueToCode(block, 'from', Blockly.JavaScript.ORDER_ATOMIC); var value_to = Blockly.JavaScript.valueToCode(block, 'to', Blockly.JavaScript.ORDER_ATOMIC); var value_by = Blockly.JavaScript.valueToCode(block, 'by', Blockly.JavaScript.ORDER_ATOMIC); var dropdown_crease = block.getFieldValue('crease'); var statements_do = Blockly.JavaScript.statementToCode(block, 'do'); let daishou; if (dropdown_crease == '+') { daishou = '<'; } else { daishou = '>'; } var code = [ `for (${value_index} = ${value_from}; ${value_index} ${daishou}= ${value_to}; ${value_index} ${dropdown_crease}= ${Math.abs(value_by)}) {`, statements_do, `}`, '' ].join('\n'); return code; }; Blockly.Python['ugj_control_for'] = function (block) { var value_index = Blockly.Python.valueToCode(block, 'index', Blockly.Python.ORDER_ATOMIC); // var variable_index = Blockly.Python.nameDB_.getName(block.getFieldValue('index'), Blockly.Variables.NAME_TYPE); var value_from = Blockly.Python.valueToCode(block, 'from', Blockly.Python.ORDER_ATOMIC); var value_to = Blockly.Python.valueToCode(block, 'to', Blockly.Python.ORDER_ATOMIC); var value_by = Blockly.Python.valueToCode(block, 'by', Blockly.Python.ORDER_ATOMIC); var dropdown_crease = block.getFieldValue('crease'); var statements_do = Blockly.Python.statementToCode(block, 'do'); if (statements_do === '') statements_do = ' pass'; if (dropdown_crease == '+') { value_by = Math.abs(value_by); value_to++; } else { value_by = Math.abs(value_by) * (-1); value_to--; } var code = [ `for ${value_index} in range(${value_from}, ${value_to}, ${value_by}) :`, statements_do, '' ].join('\n'); return code; }; Blockly.Blocks['ugj_controls_foreach'] = { init: function () { this.appendValueInput("list") .setCheck("Array") .appendField("リスト"); this.appendValueInput("item") .setCheck("Variable") .appendField("の各"); this.appendDummyInput() .appendField("について"); this.appendStatementInput("do") .setCheck(null); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setTooltip("リストの各項目について、その項目の内容を変数「項目」に代入してステートメントを実行します。"); this.setHelpUrl(""); this.setStyle('loop_blocks'); } }; Blockly.JavaScript['ugj_controls_foreach'] = function (block) { var value_list = Blockly.JavaScript.valueToCode(block, 'list', Blockly.JavaScript.ORDER_ATOMIC); var value_item = Blockly.JavaScript.valueToCode(block, 'item', Blockly.JavaScript.ORDER_ATOMIC); var statements_do = Blockly.JavaScript.statementToCode(block, 'do'); var code = [ `for (let _index in ${value_list}) {`, `${value_item} = ${value_list}[_index];`, statements_do, `}`, '' ].join('\n'); return code; }; Blockly.Python['ugj_controls_foreach'] = function (block) { var value_list = Blockly.Python.valueToCode(block, 'list', Blockly.Python.ORDER_ATOMIC); var value_item = Blockly.Python.valueToCode(block, 'item', Blockly.Python.ORDER_ATOMIC); var statements_do = Blockly.Python.statementToCode(block, 'do'); if (statements_do === '') statements_do = ' pass'; var code = [ `for ${value_item} in ${value_list}:`, statements_do, '' ].join('\n'); return code; }; // /******************/ // /** Set Interval **/ // /******************/ // Blockly.Blocks['ugj_set_interval'] = { // init: function () { // this.appendValueInput("sec") // .setCheck("Number"); // this.appendDummyInput() // .appendField("秒ごとにくり返す"); // this.appendStatementInput("do") // .setCheck(null); // this.setInputsInline(true); // this.setPreviousStatement(true, null); // this.setNextStatement(true, null); // this.setStyle('special_blocks') // this.setTooltip("非同期で繰り返し処理を行います(停止ボタンまたは停止ブロックで停止)。"); // this.setHelpUrl(""); // } // }; // Blockly.JavaScript['ugj_set_interval'] = function (block) { // var value_sec = Blockly.JavaScript.valueToCode(block, 'sec', Blockly.JavaScript.ORDER_ATOMIC); // var statements_do = Blockly.JavaScript.statementToCode(block, 'do'); // var code = [ // 'let _interval = setInterval( async () => {', // statements_do, // `}, ${value_sec}*1000);`, // '' // ].join('\n'); // return code; // }; // /******************** */ // /** Clear Interval ** */ // /******************** */ // Blockly.Blocks['ugj_special_clearinterval'] = { // init: function () { // this.appendDummyInput() // .appendField("繰り返しを停止する"); // this.setInputsInline(true); // this.setPreviousStatement(true, null); // this.setNextStatement(true, null); // this.setStyle('special_blocks') // this.setTooltip("非同期の繰り返し処理を停止します。"); // this.setHelpUrl(""); // } // }; // Blockly.JavaScript['ugj_special_clearinterval'] = function (block) { // var code = 'clearInterval(_interval);\n'; // return code; // }; // /********+********/ // /** Set Timeout **/ // /********+********/ // Blockly.Blocks['ugj_set_timeout'] = { // init: function () { // this.appendValueInput("sec") // .setCheck("Number"); // this.appendDummyInput() // .appendField("秒待ってから"); // this.appendStatementInput("do") // .setCheck(null); // this.setInputsInline(true); // this.setPreviousStatement(true, null); // this.setNextStatement(true, null); // this.setStyle('special_blocks') // this.setTooltip("指定した秒数だけ待ってから実行します。");//内側のブロック部を 外側下に接続したものは待たずに直ちに実行されます(非同期動作)。 // this.setHelpUrl(""); // } // }; // Blockly.JavaScript['ugj_set_timeout'] = function (block) { // var value_sec = Blockly.JavaScript.valueToCode(block, 'sec', Blockly.JavaScript.ORDER_ATOMIC); // var statements_do = Blockly.JavaScript.statementToCode(block, 'do'); // var code = `let _interval = setTimeout(async () => {\n${statements_do}}, ${value_sec}*1000);\n`; // return code; // };