UNPKG

iobroker.javascript

Version:
552 lines (450 loc) 19.8 kB
'use strict'; if (typeof goog !== 'undefined') { goog.provide('Blockly.JavaScript.Timeouts'); goog.require('Blockly.JavaScript'); } else { // define this object for blockly modules from adapters window.goog = { provide: function () {}, require: function () {}, }; } Blockly.CustomBlocks = Blockly.CustomBlocks || []; Blockly.CustomBlocks.push('Timeouts'); Blockly.Timeouts = { HUE: 70, blocks: {}, }; /** * Ensure two identically-named procedures don't exist. * @param {string} name Proposed procedure name. * @param {!Blockly.Block} block Block to disambiguate. * @return {string} Non-colliding name. */ Blockly.Timeouts.findLegalName = function (name, block) { if (block.isInFlyout) { // Flyouts can have multiple procedures called 'do something'. return name; } while (!Blockly.Timeouts.isLegalName_(name, block.workspace, block)) { // Collision with another procedure. const r = name.match(/^(.*?)(\d+)$/); if (!r) { name += '2'; } else { name = r[1] + (parseInt(r[2], 10) + 1); } } return name; }; /** * Does this procedure have a legal name? Illegal names include names of * procedures already defined. * @param {string} name The questionable name. * @param {!Blockly.Workspace} workspace The workspace to scan for collisions. * @param {Blockly.Block=} opt_exclude Optional block to exclude from * comparisons (one doesn't want to collide with oneself). * @return {boolean} True if the name is legal. * @private */ Blockly.Timeouts.isLegalName_ = function (name, workspace, opt_exclude) { const blocks = workspace.getAllBlocks(); // Iterate through every block and check the name. for (let i = 0; i < blocks.length; i++) { if (blocks[i] == opt_exclude) { continue; } if (blocks[i].isTimeout_ || blocks[i].isInterval_) { const blockName = blocks[i].getFieldValue('NAME'); if (Blockly.Names.equals(blockName, name)) { return false; } } } return true; }; /** * Rename a procedure. Called by the editable field. * @param {string} name The proposed new name. * @return {string} The accepted name. * @this {!Blockly.Field} */ Blockly.Timeouts.rename = function (name) { // Strip leading and trailing whitespace. Beyond this, all names are legal. name = name.replace(/^[\s\xa0]+|[\s\xa0]+$/g, ''); return Blockly.Timeouts.findLegalName(name, this.sourceBlock_); }; // --- setTimeout ----------------------------------------------------------- Blockly.Timeouts.blocks['timeouts_wait'] = '<block type="timeouts_wait">' + ' <field name="DELAY">1000</field>' + ' <field name="UNIT">ms</field>' + '</block>'; Blockly.Blocks['timeouts_wait'] = { init: function () { this.appendDummyInput() .appendField(Blockly.Translate('timeouts_wait')) .appendField(new Blockly.FieldTextInput(1000), "DELAY") .appendField(new Blockly.FieldDropdown([ [Blockly.Translate('timeouts_settimeout_ms'), 'ms'], [Blockly.Translate('timeouts_settimeout_sec'), 'sec'], [Blockly.Translate('timeouts_settimeout_min'), 'min'], ]), 'UNIT'); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setColour(Blockly.Timeouts.HUE); this.setTooltip(Blockly.Translate('timeouts_wait_tooltip')); this.setHelpUrl(getHelp('timeouts_wait_help')); }, }; Blockly.JavaScript.forBlock['timeouts_wait'] = function (block) { const fUnit = block.getFieldValue('UNIT'); let fDelay = block.getFieldValue('DELAY'); if (fUnit === 'min') { fDelay *= 60000; } else if (fUnit === 'sec') { fDelay *= 1000; } return `await wait(${fDelay});\n`; }; // --- setTimeout ----------------------------------------------------------- Blockly.Timeouts.blocks['timeouts_settimeout'] = '<block type="timeouts_settimeout">' + ' <field name="NAME">timeout</field>' + ' <field name="DELAY">1000</field>' + ' <field name="UNIT">ms</field>' + '</block>'; Blockly.Blocks['timeouts_settimeout'] = { init: function () { const nameField = new Blockly.FieldTextInput(Blockly.Timeouts.findLegalName('timeout', this), Blockly.Timeouts.rename); nameField.setSpellcheck(false); this.appendDummyInput() .appendField(Blockly.Translate('timeouts_settimeout')) .appendField(nameField, 'NAME') .appendField(Blockly.Translate('timeouts_settimeout_in')) .appendField(new Blockly.FieldTextInput(1000), 'DELAY') .appendField(new Blockly.FieldDropdown([ [Blockly.Translate('timeouts_settimeout_ms'), 'ms'], [Blockly.Translate('timeouts_settimeout_sec'), 'sec'], [Blockly.Translate('timeouts_settimeout_min'), 'min'], ]), 'UNIT'); //.appendField(Blockly.Translate('timeouts_settimeout_ms')); this.appendStatementInput('STATEMENT') .setCheck(null); this.setInputsInline(false); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setColour(Blockly.Timeouts.HUE); this.setTooltip(Blockly.Translate('timeouts_settimeout_tooltip')); this.setHelpUrl(getHelp('timeouts_settimeout_help')); }, isTimeout_: true, getVars: function () { return [this.getFieldValue('NAME')]; }, getVarModels: function () { const name = this.getFieldValue('NAME'); return [{ getId: () => { return name; }, name: name, type: 'timeout' }]; }, }; Blockly.JavaScript.forBlock['timeouts_settimeout'] = function (block) { const fName = Blockly.JavaScript.nameDB_.safeName(block.getFieldValue('NAME')); const fUnit = block.getFieldValue('UNIT'); let fDelay = block.getFieldValue('DELAY'); if (fUnit === 'min') { fDelay *= 60000; } else if (fUnit === 'sec') { fDelay *= 1000; } const statement = Blockly.JavaScript.statementToCode(block, 'STATEMENT'); return `${fName} = setTimeout(async () => {\n` + Blockly.JavaScript.prefixLines(`${fName} = null;`, Blockly.JavaScript.INDENT) + '\n' + statement + `}, ${fDelay});\n`; }; // --- setTimeout variable ----------------------------------------------------------- Blockly.Timeouts.blocks['timeouts_settimeout_variable'] = '<sep gap="5"></sep>' + '<block type="timeouts_settimeout_variable">' + ' <value name="DELAY_MS">' + ' <shadow type="math_number">' + ' <field name="NUM">1000</field>' + ' </shadow>' + ' </value>' + '</block>'; Blockly.Blocks['timeouts_settimeout_variable'] = { init: function () { const nameField = new Blockly.FieldTextInput(Blockly.Timeouts.findLegalName('timeout', this), Blockly.Timeouts.rename); nameField.setSpellcheck(false); this.appendDummyInput() .appendField(Blockly.Translate('timeouts_settimeout')) .appendField(nameField, 'NAME') .appendField(Blockly.Translate('timeouts_settimeout_in')); this.appendValueInput('DELAY_MS') .setCheck('Number') .appendField(Blockly.Translate('timeouts_settimeout_ms')); this.appendStatementInput('STATEMENT') .setCheck(null); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setColour(Blockly.Timeouts.HUE); this.setTooltip(Blockly.Translate('timeouts_settimeout_tooltip')); this.setHelpUrl(getHelp('timeouts_settimeout_help')); }, isTimeout_: true, getVars: function () { return [this.getFieldValue('NAME')]; }, getVarModels: function () { const name = this.getFieldValue('NAME'); return [{ getId: () => { return name; }, name: name, type: 'timeout' }]; }, }; Blockly.JavaScript.forBlock['timeouts_settimeout_variable'] = function (block) { const vDelayMs = Blockly.JavaScript.valueToCode(block, 'DELAY_MS', Blockly.JavaScript.ORDER_ATOMIC); const fName = Blockly.JavaScript.nameDB_.safeName(block.getFieldValue('NAME')); const statement = Blockly.JavaScript.statementToCode(block, 'STATEMENT'); return `${fName} = setTimeout(async () => {\n` + Blockly.JavaScript.prefixLines(`${fName} = null;`, Blockly.JavaScript.INDENT) + '\n' + statement + `}, parseInt(${vDelayMs}));\n`; }; // --- clearTimeout ----------------------------------------------------------- Blockly.Timeouts.getAllTimeouts = function (workspace) { const blocks = workspace.getAllBlocks(); const result = []; // Iterate through every block and check the name. for (let i = 0; i < blocks.length; i++) { if (blocks[i].isTimeout_) { result.push([blocks[i].getFieldValue('NAME'), blocks[i].getFieldValue('NAME')]); } } // BF(2020.05.16) : for back compatibility. Remove it after 5 years if (window.scripts.loading) { const variables = workspace.getVariablesOfType(''); variables.forEach(v => !result.find(it => it[0] === v.name) && result.push([v.name, v.name])); } const variables1 = workspace.getVariablesOfType('timeout'); variables1.forEach(v => !result.find(it => it[0] === v.name) && result.push([v.name, v.name])); !result.length && result.push(['', '']); return result; }; Blockly.Timeouts.blocks['timeouts_cleartimeout'] = '<sep gap="5"></sep>' + '<block type="timeouts_cleartimeout">' + ' <field name="NAME"></field>' + '</block>'; Blockly.Blocks['timeouts_cleartimeout'] = { init: function () { this.appendDummyInput('NAME') .appendField(Blockly.Translate('timeouts_cleartimeout')) .appendField(new Blockly.FieldDropdown(function () { return window.scripts && window.scripts.blocklyWorkspace ? Blockly.Timeouts.getAllTimeouts(window.scripts.blocklyWorkspace) : []; }), 'NAME'); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setColour(Blockly.Timeouts.HUE); this.setTooltip(Blockly.Translate('timeouts_cleartimeout_tooltip')); this.setHelpUrl(getHelp('timeouts_cleartimeout_help')); }, }; Blockly.JavaScript.forBlock['timeouts_cleartimeout'] = function (block) { const fName = Blockly.JavaScript.nameDB_.safeName(block.getFieldValue('NAME')); return `(() => { if (${fName}) { clearTimeout(${fName}); ${fName} = null; }})();\n`; }; // --- getTimeout ----------------------------------------------------------- Blockly.Timeouts.blocks['timeouts_gettimeout'] = '<sep gap="5"></sep>' + '<block type="timeouts_gettimeout">' + ' <field name="NAME"></field>' + '</block>'; Blockly.Blocks['timeouts_gettimeout'] = { init: function () { this.appendDummyInput('NAME') .appendField(Blockly.Translate('timeouts_gettimeout')) .appendField(new Blockly.FieldDropdown(function () { return window.scripts.blocklyWorkspace ? Blockly.Timeouts.getAllTimeouts(window.scripts.blocklyWorkspace) : []; }), 'NAME'); this.setInputsInline(true); this.setOutput(true); this.setColour(Blockly.Timeouts.HUE); this.setTooltip(Blockly.Translate('timeouts_gettimeout_tooltip')); this.setHelpUrl(getHelp('timeouts_gettimeout_help')); }, }; Blockly.JavaScript.forBlock['timeouts_gettimeout'] = function (block) { const fName = Blockly.JavaScript.nameDB_.safeName(block.getFieldValue('NAME')); return [fName, Blockly.JavaScript.ORDER_ATOMIC]; }; // --- setInterval ----------------------------------------------------------- Blockly.Timeouts.blocks['timeouts_setinterval'] = '<block type="timeouts_setinterval">' + ' <field name="INTERVAL">1000</field>' + ' <field name="UNIT">ms</field>' + '</block>'; Blockly.Blocks['timeouts_setinterval'] = { init: function () { const nameField = new Blockly.FieldTextInput(Blockly.Timeouts.findLegalName(Blockly.Translate('timeouts_setinterval_name'), this), Blockly.Timeouts.rename); nameField.setSpellcheck(false); this.appendDummyInput() .appendField(Blockly.Translate('timeouts_setinterval')) .appendField(nameField, 'NAME') .appendField(Blockly.Translate('timeouts_setinterval_in')) .appendField(new Blockly.FieldTextInput(1000), 'INTERVAL') .appendField(new Blockly.FieldDropdown([ [Blockly.Translate('timeouts_settimeout_ms'), 'ms'], [Blockly.Translate('timeouts_settimeout_sec'), 'sec'], [Blockly.Translate('timeouts_settimeout_min'), 'min'], ]), 'UNIT'); this.appendStatementInput('STATEMENT') .setCheck(null); this.setInputsInline(false); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setColour(Blockly.Timeouts.HUE); this.setTooltip(Blockly.Translate('timeouts_setinterval_tooltip')); this.setHelpUrl(getHelp('timeouts_setinterval_help')); }, isInterval_: true, getVars: function () { return [this.getFieldValue('NAME')]; }, getVarModels: function () { const name = this.getFieldValue('NAME'); return [{ getId: () => { return name; }, name: name, type: 'interval' }]; }, }; Blockly.JavaScript.forBlock['timeouts_setinterval'] = function (block) { const fName = Blockly.JavaScript.nameDB_.safeName(block.getFieldValue('NAME')); const fUnit = block.getFieldValue('UNIT'); let fInterval = block.getFieldValue('INTERVAL'); if (fUnit === 'min') { fInterval *= 60000; } else if (fUnit === 'sec') { fInterval *= 1000; } const statement = Blockly.JavaScript.statementToCode(block, 'STATEMENT'); return `${fName} = setInterval(async () => {\n` + statement + `}, ${fInterval});\n`; }; // --- setInterval variable ----------------------------------------------------------- Blockly.Timeouts.blocks['timeouts_setinterval_variable'] = '<sep gap="5"></sep>' + '<block type="timeouts_setinterval_variable">' + ' <value name="INTERVAL_MS">' + ' <shadow type="math_number">' + ' <field name="NUM">1000</field>' + ' </shadow>' + ' </value>' + '</block>'; Blockly.Blocks['timeouts_setinterval_variable'] = { init: function () { const nameField = new Blockly.FieldTextInput( Blockly.Timeouts.findLegalName(Blockly.Translate('timeouts_setinterval_name'), this), Blockly.Timeouts.rename); nameField.setSpellcheck(false); this.appendDummyInput() .appendField(Blockly.Translate('timeouts_setinterval')) .appendField(nameField, 'NAME') .appendField(Blockly.Translate('timeouts_setinterval_in')); this.appendValueInput('INTERVAL_MS') .setCheck('Number') .appendField(Blockly.Translate('timeouts_settimeout_ms')); this.appendStatementInput('STATEMENT') .setCheck(null); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setColour(Blockly.Timeouts.HUE); this.setTooltip(Blockly.Translate('timeouts_setinterval_tooltip')); this.setHelpUrl(getHelp('timeouts_setinterval_help')); }, isInterval_: true, getVars: function () { return [this.getFieldValue('NAME')]; }, getVarModels: function () { const name = this.getFieldValue('NAME'); return [{ getId: () => { return name; }, name: name, type: 'interval' }]; }, }; Blockly.JavaScript.forBlock['timeouts_setinterval_variable'] = function (block) { const vIntervalMs = Blockly.JavaScript.valueToCode(block, 'INTERVAL_MS', Blockly.JavaScript.ORDER_ATOMIC); const fName = Blockly.JavaScript.nameDB_.safeName(block.getFieldValue('NAME')); const statement = Blockly.JavaScript.statementToCode(block, 'STATEMENT'); return `${fName} = setInterval(async () => {\n` + statement + `}, parseInt(${vIntervalMs}));\n`; }; // --- clearInterval ----------------------------------------------------------- Blockly.Timeouts.blocks['timeouts_clearinterval'] = '<sep gap="5"></sep>' + '<block type="timeouts_clearinterval">' + ' <field name="NAME"></field>' + '</block>'; Blockly.Timeouts.getAllIntervals = function (workspace) { const blocks = workspace.getAllBlocks(); const result = []; // Iterate through every block and check the name. for (let i = 0; i < blocks.length; i++) { if (blocks[i].isInterval_) { result.push([blocks[i].getFieldValue('NAME'), blocks[i].getFieldValue('NAME')]); } } // BF(2020.05.16) : for back compatibility. Remove it after 5 years if (window.scripts.loading) { const variables = workspace.getVariablesOfType(''); variables.forEach(v => !result.find(it => it[0] === v.name) && result.push([v.name, v.name])); } const variables1 = workspace.getVariablesOfType('interval'); variables1.forEach(v => !result.find(it => it[0] === v.name) && result.push([v.name, v.name])); !result.length && result.push(['', '']); return result; }; Blockly.Blocks['timeouts_clearinterval'] = { init: function () { this.appendDummyInput('NAME') .appendField(Blockly.Translate('timeouts_clearinterval')) .appendField(new Blockly.FieldDropdown(function () { return window.scripts.blocklyWorkspace ? Blockly.Timeouts.getAllIntervals(window.scripts.blocklyWorkspace) : []; }), 'NAME'); this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setColour(Blockly.Timeouts.HUE); this.setTooltip(Blockly.Translate('timeouts_clearinterval_tooltip')); this.setHelpUrl(getHelp('timeouts_clearinterval_help')); }, }; Blockly.JavaScript.forBlock['timeouts_clearinterval'] = function (block) { const fName = Blockly.JavaScript.nameDB_.safeName(block.getFieldValue('NAME')); return `(() => { if (${fName}) { clearInterval(${fName}); ${fName} = null; }})();\n`; }; // --- getInterval ----------------------------------------------------------- Blockly.Timeouts.blocks['timeouts_getinterval'] = '<sep gap="5"></sep>' + '<block type="timeouts_getinterval">' + ' <field name="NAME"></field>' + '</block>'; Blockly.Blocks['timeouts_getinterval'] = { init: function () { this.appendDummyInput('NAME') .appendField(Blockly.Translate('timeouts_getinterval')) .appendField(new Blockly.FieldDropdown(function () { return window.scripts.blocklyWorkspace ? Blockly.Timeouts.getAllIntervals(window.scripts.blocklyWorkspace) : []; }), 'NAME'); this.setInputsInline(true); this.setOutput(true); this.setColour(Blockly.Timeouts.HUE); this.setTooltip(Blockly.Translate('timeouts_getinterval_tooltip')); this.setHelpUrl(getHelp('timeouts_getinterval_help')); }, }; Blockly.JavaScript.forBlock['timeouts_getinterval'] = function (block) { const fName = Blockly.JavaScript.nameDB_.safeName(block.getFieldValue('NAME')); return [fName, Blockly.JavaScript.ORDER_ATOMIC]; };