858 lines
32 KiB
JavaScript
858 lines
32 KiB
JavaScript
'use strict';
|
|
|
|
goog.provide('Blockly.JavaScript.Trigger');
|
|
|
|
goog.require('Blockly.JavaScript');
|
|
|
|
Blockly.CustomBlocks = Blockly.CustomBlocks || [];
|
|
Blockly.CustomBlocks.push('Trigger');
|
|
|
|
|
|
Blockly.Trigger = {
|
|
HUE: 330,
|
|
blocks: {}
|
|
};
|
|
|
|
// --- ON Extended-----------------------------------------------------------
|
|
Blockly.Trigger.blocks['on_ext'] =
|
|
'<block type="on_ext">'
|
|
+ ' <value name="CONDITION">'
|
|
+ ' </value>'
|
|
+ ' <value name="ACK_CONDITION">'
|
|
+ ' </value>'
|
|
+ ' <value name="STATEMENT">'
|
|
+ ' </value>'
|
|
+ '</block>';
|
|
|
|
Blockly.Blocks['on_ext_oid_container'] = {
|
|
/**
|
|
* Mutator block for container.
|
|
* @this Blockly.Block
|
|
*/
|
|
init: function() {
|
|
this.setColour(Blockly.Trigger.HUE);
|
|
|
|
this.appendDummyInput()
|
|
.appendField(Blockly.Words['on_ext_on'][systemLang]);
|
|
|
|
this.appendStatementInput('STACK');
|
|
this.setTooltip(Blockly.Words['on_ext_on_tooltip'][systemLang]);
|
|
this.contextMenu = false;
|
|
}
|
|
};
|
|
|
|
Blockly.Blocks['on_ext_oid'] = {
|
|
/**
|
|
* Mutator block for add items.
|
|
* @this Blockly.Block
|
|
*/
|
|
init: function() {
|
|
this.setColour(Blockly.Trigger.HUE);
|
|
|
|
this.appendDummyInput('OID')
|
|
.appendField(Blockly.Words['on_ext_oid'][systemLang]);
|
|
|
|
this.setPreviousStatement(true);
|
|
this.setNextStatement(true);
|
|
|
|
this.setTooltip(Blockly.Words['on_ext_oid_tooltip'][systemLang]);
|
|
|
|
this.contextMenu = false;
|
|
}
|
|
};
|
|
|
|
Blockly.Blocks['on_ext'] = {
|
|
init: function() {
|
|
this.itemCount_ = 1;
|
|
this.updateShape_();
|
|
|
|
this.setMutator(new Blockly.Mutator(['on_ext_oid']));
|
|
|
|
this.setPreviousStatement(true, null);
|
|
this.setNextStatement(true, null);
|
|
this.setInputsInline(false);
|
|
this.setColour(Blockly.Trigger.HUE);
|
|
this.setTooltip(Blockly.Words['on_ext_tooltip'][systemLang]);
|
|
this.setHelpUrl(getHelp('on_help'));
|
|
},
|
|
/**
|
|
* Create XML to represent number of text inputs.
|
|
* @return {!Element} XML storage element.
|
|
* @this Blockly.Block
|
|
*/
|
|
mutationToDom: function () {
|
|
var container = document.createElement('mutation');
|
|
container.setAttribute('items', this.itemCount_);
|
|
return container;
|
|
},
|
|
/**
|
|
* Parse XML to restore the text inputs.
|
|
* @param {!Element} xmlElement XML storage element.
|
|
* @this Blockly.Block
|
|
*/
|
|
domToMutation: function (xmlElement) {
|
|
this.itemCount_ = parseInt(xmlElement.getAttribute('items'), 10);
|
|
this.updateShape_();
|
|
},
|
|
/**
|
|
* Populate the mutator's dialog with this block's components.
|
|
* @param {!Blockly.Workspace} workspace Mutator's workspace.
|
|
* @return {!Blockly.Block} Root block in mutator.
|
|
* @this Blockly.Block
|
|
*/
|
|
decompose: function (workspace) {
|
|
var containerBlock = workspace.newBlock('on_ext_oid_container');
|
|
containerBlock.initSvg();
|
|
var connection = containerBlock.getInput('STACK').connection;
|
|
for (var i = 0; i < this.itemCount_; i++) {
|
|
var itemBlock = workspace.newBlock('on_ext_oid');
|
|
itemBlock.initSvg();
|
|
connection.connect(itemBlock.previousConnection);
|
|
connection = itemBlock.nextConnection;
|
|
}
|
|
return containerBlock;
|
|
},
|
|
/**
|
|
* Reconfigure this block based on the mutator dialog's components.
|
|
* @param {!Blockly.Block} containerBlock Root block in mutator.
|
|
* @this Blockly.Block
|
|
*/
|
|
compose: function (containerBlock) {
|
|
var itemBlock = containerBlock.getInputTargetBlock('STACK');
|
|
// Count number of inputs.
|
|
var connections = [];
|
|
while (itemBlock) {
|
|
connections.push(itemBlock.valueConnection_);
|
|
itemBlock = itemBlock.nextConnection &&
|
|
itemBlock.nextConnection.targetBlock();
|
|
}
|
|
// Disconnect any children that don't belong.
|
|
for (var i = 0; i < this.itemCount_; i++) {
|
|
var connection = this.getInput('OID' + i).connection.targetConnection;
|
|
if (connection && connections.indexOf(connection) === -1) {
|
|
connection.disconnect();
|
|
}
|
|
}
|
|
this.itemCount_ = connections.length;
|
|
if (this.itemCount_ < 1) this.itemCount_ = 1;
|
|
this.updateShape_();
|
|
// Reconnect any child blocks.
|
|
for (var i = 0; i < this.itemCount_; i++) {
|
|
Blockly.Mutator.reconnect(connections[i], this, 'OID' + i);
|
|
}
|
|
},
|
|
/**
|
|
* Store pointers to any connected child blocks.
|
|
* @param {!Blockly.Block} containerBlock Root block in mutator.
|
|
* @this Blockly.Block
|
|
*/
|
|
saveConnections: function(containerBlock) {
|
|
var itemBlock = containerBlock.getInputTargetBlock('STACK');
|
|
var i = 0;
|
|
while (itemBlock) {
|
|
var input = this.getInput('OID' + i);
|
|
itemBlock.valueConnection_ = input && input.connection.targetConnection;
|
|
i++;
|
|
itemBlock = itemBlock.nextConnection &&
|
|
itemBlock.nextConnection.targetBlock();
|
|
}
|
|
},
|
|
/**
|
|
* Modify this block to have the correct number of inputs.
|
|
* @private
|
|
* @this Blockly.Block
|
|
*/
|
|
updateShape_: function() {
|
|
this.removeInput('CONDITION');
|
|
this.removeInput('ACK_CONDITION');
|
|
var input;
|
|
|
|
for (var j = 0; input = this.inputList[j]; j++) {
|
|
if (input.name === 'STATEMENT') {
|
|
this.inputList.splice(j, 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Add new inputs.
|
|
for (var i = 0; i < this.itemCount_; i++) {
|
|
var _input = this.getInput('OID' + i);
|
|
if (!_input) {
|
|
_input = this.appendValueInput('OID' + i);
|
|
|
|
if (i === 0) {
|
|
_input.appendField(Blockly.Words['on_ext'][systemLang]);
|
|
}
|
|
var shadow = this.workspace.newBlock('field_oid');
|
|
shadow.setShadow(true);
|
|
shadow.outputConnection.connect(_input.connection);
|
|
shadow.initSvg();
|
|
shadow.render();
|
|
} else {
|
|
if (!_input.connection.isConnected()) {
|
|
var shadow = this.workspace.newBlock('field_oid');
|
|
shadow.setShadow(true);
|
|
shadow.outputConnection.connect(_input.connection);
|
|
shadow.initSvg();
|
|
shadow.render();
|
|
}
|
|
}
|
|
}
|
|
// Remove deleted inputs.
|
|
while (this.getInput('OID' + i)) {
|
|
this.removeInput('OID' + i);
|
|
i++;
|
|
}
|
|
|
|
this.appendDummyInput('CONDITION')
|
|
.appendField(new Blockly.FieldDropdown([
|
|
[Blockly.Words['on_onchange'][systemLang], 'ne'],
|
|
[Blockly.Words['on_any'][systemLang], 'any'],
|
|
[Blockly.Words['on_gt'][systemLang], 'gt'],
|
|
[Blockly.Words['on_ge'][systemLang], 'ge'],
|
|
[Blockly.Words['on_lt'][systemLang], 'lt'],
|
|
[Blockly.Words['on_le'][systemLang], 'le'],
|
|
[Blockly.Words['on_true'][systemLang], 'true'],
|
|
[Blockly.Words['on_false'][systemLang], 'false']
|
|
]), 'CONDITION');
|
|
|
|
this.appendDummyInput('ACK_CONDITION')
|
|
.appendField(Blockly.Words['on_ack'][systemLang])
|
|
.appendField(new Blockly.FieldDropdown([
|
|
[Blockly.Words['on_ack_any'][systemLang], ''],
|
|
[Blockly.Words['on_ack_true'][systemLang], 'true'],
|
|
[Blockly.Words['on_ack_false'][systemLang], 'false']
|
|
]), 'ACK_CONDITION');
|
|
|
|
if (input) {
|
|
this.inputList.push(input);
|
|
}
|
|
else {
|
|
this.appendStatementInput('STATEMENT')
|
|
.setCheck(null)
|
|
}
|
|
}
|
|
};
|
|
Blockly.JavaScript['on_ext'] = function(block) {
|
|
var dropdown_condition = block.getFieldValue('CONDITION');
|
|
var statements_name = Blockly.JavaScript.statementToCode(block, 'STATEMENT');
|
|
var ack_condition = block.getFieldValue('ACK_CONDITION');
|
|
var val;
|
|
if (dropdown_condition === 'true' || dropdown_condition === 'false') {
|
|
val = 'val: ' + dropdown_condition;
|
|
} else {
|
|
val = 'change: "' + dropdown_condition + '"';
|
|
}
|
|
|
|
var oids = [];
|
|
var firstID;
|
|
for (var n = 0; n < block.itemCount_; n++) {
|
|
var id = Blockly.JavaScript.valueToCode(block, 'OID' + n, Blockly.JavaScript.ORDER_COMMA);
|
|
if (id) {
|
|
firstID = id;
|
|
id = id.replace(/\./g, '\\\\.').replace(/\(/g, '\\\\(').replace(/\)/g, '\\\\)').replace(/\[/g, '\\\\[');
|
|
if (oids.indexOf(id) === -1) oids.push(id);
|
|
}
|
|
}
|
|
var oid;
|
|
if (oids.length === 1) {
|
|
oid = firstID;
|
|
} else {
|
|
oid = 'new RegExp(' + (oids.join(' + "|" + ') || '') + ')';
|
|
}
|
|
|
|
|
|
var code = 'on({id: ' + oid + ', ' + val + (ack_condition ? ', ack: ' + ack_condition : '') + '}, function (obj) {\n ' +
|
|
(oids.length === 1 ? 'var value = obj.state.val;\n var oldValue = obj.oldState.val;\n' : '') +
|
|
statements_name + '});\n';
|
|
return code;
|
|
};
|
|
|
|
// --- ON -----------------------------------------------------------
|
|
Blockly.Trigger.blocks['on'] =
|
|
'<block type="on">'
|
|
+ ' <value name="OID">'
|
|
+ ' </value>'
|
|
+ ' <value name="CONDITION">'
|
|
+ ' </value>'
|
|
+ ' <value name="ACK_CONDITION">'
|
|
+ ' </value>'
|
|
+ ' <value name="STATEMENT">'
|
|
+ ' </value>'
|
|
+ '</block>';
|
|
|
|
Blockly.Blocks['on'] = {
|
|
init: function() {
|
|
this.appendDummyInput()
|
|
.appendField(Blockly.Words['on'][systemLang]);
|
|
|
|
this.appendDummyInput('OID')
|
|
.appendField(new Blockly.FieldOID('Object ID', main.initSelectId(), main.objects), 'OID');
|
|
|
|
this.appendDummyInput('CONDITION')
|
|
.appendField(new Blockly.FieldDropdown([
|
|
[Blockly.Words['on_onchange'][systemLang], 'ne'],
|
|
[Blockly.Words['on_any'][systemLang], 'any'],
|
|
[Blockly.Words['on_gt'][systemLang], 'gt'],
|
|
[Blockly.Words['on_ge'][systemLang], 'ge'],
|
|
[Blockly.Words['on_lt'][systemLang], 'lt'],
|
|
[Blockly.Words['on_le'][systemLang], 'le'],
|
|
[Blockly.Words['on_true'][systemLang], 'true'],
|
|
[Blockly.Words['on_false'][systemLang], 'false']
|
|
]), 'CONDITION');
|
|
|
|
this.appendDummyInput('ACK_CONDITION')
|
|
.appendField(Blockly.Words['on_ack'][systemLang])
|
|
.appendField(new Blockly.FieldDropdown([
|
|
[Blockly.Words['on_ack_any'][systemLang], ''],
|
|
[Blockly.Words['on_ack_true'][systemLang], 'true'],
|
|
[Blockly.Words['on_ack_false'][systemLang], 'false']
|
|
]), 'ACK_CONDITION');
|
|
|
|
this.appendStatementInput('STATEMENT')
|
|
.setCheck(null);
|
|
|
|
this.setPreviousStatement(true, null);
|
|
this.setNextStatement(true, null);
|
|
this.setInputsInline(false);
|
|
this.setColour(Blockly.Trigger.HUE);
|
|
this.setTooltip(Blockly.Words['on_tooltip'][systemLang]);
|
|
this.setHelpUrl(getHelp('on_help'));
|
|
}
|
|
};
|
|
Blockly.JavaScript['on'] = function(block) {
|
|
var value_objectid = block.getFieldValue('OID');
|
|
var dropdown_condition = block.getFieldValue('CONDITION');
|
|
var ack_condition = block.getFieldValue('ACK_CONDITION');
|
|
var statements_name = Blockly.JavaScript.statementToCode(block, 'STATEMENT');
|
|
var objectname = main.objects[value_objectid] && main.objects[value_objectid].common && main.objects[value_objectid].common.name ? main.objects[value_objectid].common.name : '';
|
|
|
|
Blockly.Msg.VARIABLES_DEFAULT_NAME = 'value';
|
|
|
|
var val;
|
|
if (dropdown_condition === 'true' || dropdown_condition === 'false') {
|
|
val = 'val: ' + dropdown_condition;
|
|
} else {
|
|
val = 'change: "' + dropdown_condition + '"';
|
|
}
|
|
|
|
var code = 'on({id: "' + value_objectid + '"' + (objectname ? '/*' + objectname + '*/' : '') + ', ' + val + (ack_condition ? ', ack: ' + ack_condition : '') + '}, function (obj) {\n var value = obj.state.val;\n var oldValue = obj.oldState.val;\n' + statements_name + '});\n';
|
|
return code;
|
|
};
|
|
|
|
// --- get info about event -----------------------------------------------------------
|
|
Blockly.Trigger.blocks['on_source'] =
|
|
'<block type="on_source">'
|
|
+ ' <value name="ATTR">'
|
|
+ ' </value>'
|
|
+ '</block>';
|
|
|
|
Blockly.Blocks['on_source'] = {
|
|
/**
|
|
* Block for conditionally returning a value from a procedure.
|
|
* @this Blockly.Block
|
|
*/
|
|
init: function() {
|
|
this.appendDummyInput('ATTR')
|
|
.appendField(new Blockly.FieldDropdown([
|
|
[Blockly.Words['on_source_id'][systemLang], 'id'],
|
|
[Blockly.Words['on_source_name'][systemLang], 'common.name'],
|
|
[Blockly.Words['on_source_desc'][systemLang], 'common.desc'],
|
|
[Blockly.Words['on_source_channel_id'][systemLang], 'channelId'],
|
|
[Blockly.Words['on_source_channel_name'][systemLang], 'channelName'],
|
|
[Blockly.Words['on_source_device_id'][systemLang], 'deviceId'],
|
|
[Blockly.Words['on_source_device_name'][systemLang], 'deviceName'],
|
|
[Blockly.Words['on_source_state_val'][systemLang], 'state.val'],
|
|
[Blockly.Words['on_source_state_ts'][systemLang], 'state.ts'],
|
|
[Blockly.Words['on_source_state_q'][systemLang], 'state.q'],
|
|
[Blockly.Words['on_source_state_from'][systemLang], 'state.from'],
|
|
[Blockly.Words['on_source_state_ack'][systemLang], 'state.ack'],
|
|
[Blockly.Words['on_source_state_lc'][systemLang], 'state.lc'],
|
|
[Blockly.Words['on_source_oldstate_val'][systemLang], 'oldState.val'],
|
|
[Blockly.Words['on_source_oldstate_ts'][systemLang], 'oldState.ts'],
|
|
[Blockly.Words['on_source_oldstate_q'][systemLang], 'oldState.q'],
|
|
[Blockly.Words['on_source_oldstate_from'][systemLang], 'oldState.from'],
|
|
[Blockly.Words['on_source_oldstate_ack'][systemLang], 'oldState.ack'],
|
|
[Blockly.Words['on_source_oldstate_lc'][systemLang], 'oldState.lc']
|
|
]), 'ATTR');
|
|
|
|
this.setInputsInline(true);
|
|
this.setOutput(true);
|
|
this.setColour(Blockly.Trigger.HUE);
|
|
this.setTooltip(Blockly.Words['on_source_tooltip'][systemLang]);
|
|
this.setHelpUrl(getHelp('on_help'));
|
|
},
|
|
/**
|
|
* Called whenever anything on the workspace changes.
|
|
* Add warning if this flow block is not nested inside a loop.
|
|
* @param {!Blockly.Events.Abstract} e Change event.
|
|
* @this Blockly.Block
|
|
*/
|
|
onchange: function(e) {
|
|
var legal = false;
|
|
// Is the block nested in a trigger?
|
|
var block = this;
|
|
do {
|
|
if (this.FUNCTION_TYPES.indexOf(block.type) !== -1) {
|
|
legal = true;
|
|
break;
|
|
}
|
|
block = block.getSurroundParent();
|
|
} while (block);
|
|
|
|
if (legal) {
|
|
this.setWarningText(null);
|
|
} else {
|
|
this.setWarningText(Blockly.Words['on_source_warning'][systemLang]);
|
|
}
|
|
},
|
|
/**
|
|
* List of block types that are functions and thus do not need warnings.
|
|
* To add a new function type add this to your code:
|
|
* Blockly.Blocks['procedures_ifreturn'].FUNCTION_TYPES.push('custom_func');
|
|
*/
|
|
FUNCTION_TYPES: ['on', 'on_ext']
|
|
};
|
|
Blockly.JavaScript['on_source'] = function(block) {
|
|
var attr = block.getFieldValue('ATTR');
|
|
var parts = attr.split('.');
|
|
if (parts.length > 1) {
|
|
attr = '(obj.' + parts[0] + ' ? obj.' + attr + ' : "")';
|
|
} else {
|
|
attr = 'obj.' + attr;
|
|
}
|
|
return [attr, Blockly.JavaScript.ORDER_ATOMIC];
|
|
};
|
|
|
|
// --- SCHEDULE -----------------------------------------------------------
|
|
Blockly.Trigger.blocks['schedule'] =
|
|
'<block type="schedule">'
|
|
+ ' <value name="SCHEDULE">'
|
|
//+ ' <shadow type="text">'
|
|
//+ ' <field name="TEXT">test</field>'
|
|
//+ ' </shadow>'
|
|
+ ' </value>'
|
|
+ ' <value name="STATEMENT">'
|
|
+ ' </value>'
|
|
+ '</block>';
|
|
|
|
Blockly.Blocks['schedule'] = {
|
|
init: function() {
|
|
this.appendDummyInput()
|
|
.appendField(Blockly.Words['schedule'][systemLang]);
|
|
|
|
this.appendDummyInput('SCHEDULE')
|
|
.appendField(new Blockly.FieldCRON('* * * * *'), 'SCHEDULE');
|
|
|
|
this.appendStatementInput('STATEMENT')
|
|
.setCheck(null);
|
|
|
|
this.setPreviousStatement(true, null);
|
|
this.setNextStatement(true, null);
|
|
this.setInputsInline(false);
|
|
this.setColour(Blockly.Trigger.HUE);
|
|
this.setTooltip(Blockly.Words['schedule_tooltip'][systemLang]);
|
|
this.setHelpUrl(getHelp('schedule_help'));
|
|
}
|
|
};
|
|
Blockly.JavaScript['schedule'] = function(block) {
|
|
var schedule = block.getFieldValue('SCHEDULE');
|
|
var statements_name = Blockly.JavaScript.statementToCode(block, 'STATEMENT');
|
|
|
|
return 'schedule("' + schedule +'", function () {\n' + statements_name + '});\n';
|
|
};
|
|
|
|
// --- ASTRO -----------------------------------------------------------
|
|
Blockly.Trigger.blocks['astro'] =
|
|
'<block type="astro">'
|
|
+ ' <value name="TYPE">'
|
|
//+ ' <shadow type="text">'
|
|
//+ ' <field name="TEXT">test</field>'
|
|
//+ ' </shadow>'
|
|
+ ' </value>'
|
|
+ ' <value name="OFFSET">'
|
|
+ ' </value>'
|
|
+ ' <value name="STATEMENT">'
|
|
+ ' </value>'
|
|
+ '</block>';
|
|
|
|
Blockly.Blocks['astro'] = {
|
|
init: function() {
|
|
this.appendDummyInput()
|
|
.appendField(Blockly.Words['astro'][systemLang]);
|
|
|
|
this.appendDummyInput("TYPE")
|
|
.appendField(new Blockly.FieldDropdown([
|
|
[Blockly.Words['astro_sunriseText'][systemLang], "sunrise"],
|
|
[Blockly.Words['astro_sunriseEndText'][systemLang], "sunriseEnd"],
|
|
[Blockly.Words['astro_goldenHourEndText'][systemLang], "goldenHourEnd"],
|
|
[Blockly.Words['astro_solarNoonText'][systemLang], "solarNoon"],
|
|
[Blockly.Words['astro_goldenHourText'][systemLang], "goldenHour"],
|
|
[Blockly.Words['astro_sunsetStartText'][systemLang], "sunsetStart"],
|
|
[Blockly.Words['astro_sunsetText'][systemLang], "sunset"],
|
|
[Blockly.Words['astro_duskText'][systemLang], "dusk"],
|
|
[Blockly.Words['astro_nauticalDuskText'][systemLang], "nauticalDusk"],
|
|
[Blockly.Words['astro_nightText'][systemLang], "night"],
|
|
[Blockly.Words['astro_nightEndText'][systemLang], "nightEnd"],
|
|
[Blockly.Words['astro_nauticalDawnText'][systemLang], "nauticalDawn"],
|
|
[Blockly.Words['astro_dawnText'][systemLang], "dawn"],
|
|
[Blockly.Words['astro_nadirText'][systemLang], "nadir"]
|
|
]), 'TYPE');
|
|
|
|
this.appendDummyInput()
|
|
.appendField(Blockly.Words['astro_offset'][systemLang]);
|
|
|
|
this.appendDummyInput("OFFSET")
|
|
.appendField(new Blockly.FieldTextInput("0"), "OFFSET");
|
|
|
|
this.appendDummyInput()
|
|
.appendField(Blockly.Words['astro_minutes'][systemLang]);
|
|
|
|
this.appendStatementInput('STATEMENT')
|
|
.setCheck(null);
|
|
this.setInputsInline(true);
|
|
|
|
this.setPreviousStatement(true, null);
|
|
this.setNextStatement(true, null);
|
|
this.setColour(Blockly.Trigger.HUE);
|
|
this.setTooltip(Blockly.Words['astro_tooltip'][systemLang]);
|
|
this.setHelpUrl(getHelp('astro_help'));
|
|
}
|
|
};
|
|
Blockly.JavaScript['astro'] = function(block) {
|
|
var astrotype = block.getFieldValue('TYPE');
|
|
var offset = parseInt(block.getFieldValue('OFFSET'), 10);
|
|
var statements_name = Blockly.JavaScript.statementToCode(block, 'STATEMENT');
|
|
|
|
return 'schedule({astro: "' + astrotype + '", shift: ' + offset + '}, function () {\n' + statements_name + '});\n';
|
|
};
|
|
|
|
// --- set named schedule -----------------------------------------------------------
|
|
Blockly.Trigger.blocks['schedule_create'] =
|
|
'<block type="schedule_create">'
|
|
+ ' <value name="NAME">'
|
|
+ ' </value>'
|
|
+ ' <value name="SCHEDULE">'
|
|
+ ' <shadow type="field_cron">'
|
|
+ ' <field name="CRON">* * * * *</field>'
|
|
+ ' </shadow>'
|
|
+ ' </value>'
|
|
+ ' <value name="STATEMENT">'
|
|
+ ' </value>'
|
|
+ '</block>';
|
|
/**
|
|
* 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.Trigger.findLegalName = function(name, block) {
|
|
if (block.isInFlyout) {
|
|
// Flyouts can have multiple procedures called 'do something'.
|
|
return name;
|
|
}
|
|
while (!Blockly.Trigger.isLegalName_(name, block.workspace, block)) {
|
|
// Collision with another procedure.
|
|
var 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.Trigger.isLegalName_ = function(name, workspace, opt_exclude) {
|
|
var blocks = workspace.getAllBlocks();
|
|
// Iterate through every block and check the name.
|
|
for (var i = 0; i < blocks.length; i++) {
|
|
if (blocks[i] == opt_exclude) {
|
|
continue;
|
|
}
|
|
if (blocks[i].isSchedule_) {
|
|
var 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.Trigger.rename = function (name) {
|
|
// Strip leading and trailing whitespace. Beyond this, all names are legal.
|
|
name = name.replace(/^[\s\xa0]+|[\s\xa0]+$/g, '');
|
|
return Blockly.Trigger.findLegalName(name, this.sourceBlock_);
|
|
};
|
|
|
|
Blockly.Blocks['schedule_create'] = {
|
|
init: function() {
|
|
var nameField = new Blockly.FieldTextInput(
|
|
Blockly.Trigger.findLegalName('schedule', this),
|
|
Blockly.Trigger.rename);
|
|
|
|
nameField.setSpellcheck(false);
|
|
|
|
this.appendDummyInput('NAME')
|
|
.appendField(Blockly.Words['schedule_create'][systemLang])
|
|
.appendField(nameField, 'NAME');
|
|
|
|
this.appendValueInput('SCHEDULE')
|
|
.appendField(Blockly.Words['schedule_text'][systemLang]);
|
|
|
|
this.appendStatementInput('STATEMENT')
|
|
.setCheck(null);
|
|
|
|
this.setPreviousStatement(true, null);
|
|
this.setNextStatement(true, null);
|
|
this.setInputsInline(false);
|
|
this.setColour(Blockly.Trigger.HUE);
|
|
this.setTooltip(Blockly.Words['schedule_create_tooltip'][systemLang]);
|
|
this.setHelpUrl(getHelp('schedule_create_help'));
|
|
},
|
|
isSchedule_: true,
|
|
getVars: function () {
|
|
return [this.getFieldValue('NAME')];
|
|
}
|
|
};
|
|
|
|
Blockly.JavaScript['schedule_create'] = function(block) {
|
|
var name = block.getFieldValue('NAME');
|
|
var schedule = Blockly.JavaScript.valueToCode(block, 'SCHEDULE', Blockly.JavaScript.ORDER_ATOMIC);
|
|
var statements_name = Blockly.JavaScript.statementToCode(block, 'STATEMENT');
|
|
|
|
return name + ' = schedule(' + schedule + ', function () {\n' + statements_name + '});\n';
|
|
};
|
|
|
|
// --- clearSchedule -----------------------------------------------------------
|
|
Blockly.Trigger.getAllSchedules = function (workspace) {
|
|
var blocks = workspace.getAllBlocks();
|
|
var result = [];
|
|
|
|
// Iterate through every block and check the name.
|
|
for (var i = 0; i < blocks.length; i++) {
|
|
if (blocks[i].isSchedule_) {
|
|
result.push([blocks[i].getFieldValue('NAME'), blocks[i].getFieldValue('NAME')]);
|
|
}
|
|
}
|
|
if (!result.length) result.push(['', '']);
|
|
|
|
return result;
|
|
};
|
|
|
|
Blockly.Trigger.blocks['schedule_clear'] =
|
|
'<block type="schedule_clear">'
|
|
+ ' <value name="NAME">'
|
|
+ ' </value>'
|
|
+ '</block>';
|
|
|
|
Blockly.Blocks['schedule_clear'] = {
|
|
init: function() {
|
|
this.appendDummyInput('NAME')
|
|
.appendField(Blockly.Words['schedule_clear'][systemLang])
|
|
.appendField(new Blockly.FieldDropdown(function () {
|
|
return Blockly.Trigger.getAllSchedules(scripts.blocklyWorkspace);
|
|
}), 'NAME');
|
|
|
|
this.setPreviousStatement(true, null);
|
|
this.setNextStatement(true, null);
|
|
this.setInputsInline(true);
|
|
this.setColour(Blockly.Trigger.HUE);
|
|
this.setTooltip(Blockly.Words['schedule_clear_tooltip'][systemLang]);
|
|
this.setHelpUrl(getHelp('schedule_clear_help'));
|
|
}
|
|
};
|
|
|
|
Blockly.JavaScript['schedule_clear'] = function(block) {
|
|
var name = block.getFieldValue('NAME');
|
|
return '(function () {if (' + name + ') {clearSchedule(' + name + '); ' + name + ' = null;}})();\n';
|
|
};
|
|
|
|
// --- CRON dialog --------------------------------------------------
|
|
Blockly.Trigger.blocks['field_cron'] =
|
|
'<block type="field_cron">'
|
|
+ ' <value name="CRON">'
|
|
+ ' </value>'
|
|
+ '</block>';
|
|
|
|
Blockly.Blocks['field_cron'] = {
|
|
// Checkbox.
|
|
init: function() {
|
|
this.appendDummyInput()
|
|
.appendField(Blockly.Words['field_cron_CRON'][systemLang]);
|
|
|
|
this.appendDummyInput()
|
|
.appendField(new Blockly.FieldCRON('* * * * *'), 'CRON');
|
|
|
|
this.setInputsInline(true);
|
|
this.setColour(Blockly.Trigger.HUE);
|
|
this.setOutput(true, 'String');
|
|
this.setTooltip(Blockly.Words['field_cron_tooltip'][systemLang]);
|
|
}
|
|
};
|
|
|
|
Blockly.JavaScript['field_cron'] = function(block) {
|
|
var oid = block.getFieldValue('CRON');
|
|
return ['\'' + oid + '\'', Blockly.JavaScript.ORDER_ATOMIC]
|
|
};
|
|
|
|
// --- CRON builder --------------------------------------------------
|
|
Blockly.Trigger.blocks['cron_builder'] =
|
|
'<block type="cron_builder">'
|
|
+ ' <value name="LINE">'
|
|
+ ' </value>'
|
|
+ ' <value name="MINUTES">'
|
|
+ ' </value>'
|
|
+ ' <value name="HOURS">'
|
|
+ ' </value>'
|
|
+ ' <value name="DAYS">'
|
|
+ ' </value>'
|
|
+ ' <value name="MONTHS">'
|
|
+ ' </value>'
|
|
+ ' <value name="WEEKDAYS">'
|
|
+ ' </value>'
|
|
+ ' <value name="WITH_SECONDS">'
|
|
+ ' </value>'
|
|
+ ' <mutation seconds="false"></mutation>'
|
|
+ '</block>';
|
|
|
|
Blockly.Blocks['cron_builder'] = {
|
|
// Checkbox.
|
|
init: function() {
|
|
|
|
this.appendDummyInput()
|
|
.appendField(Blockly.Words['cron_builder_CRON'][systemLang]);
|
|
|
|
this.appendDummyInput('LINE')
|
|
.appendField(Blockly.Words['cron_builder_line'][systemLang])
|
|
.appendField(new Blockly.FieldCheckbox('FALSE', function (option) {
|
|
this.sourceBlock_.setInputsInline(option == true);
|
|
}), 'LINE');
|
|
|
|
var _input = this.appendValueInput('DOW')
|
|
.appendField(Blockly.Words['cron_builder_dow'][systemLang]);
|
|
var _shadow = this.workspace.newBlock('text');
|
|
_shadow.setShadow(true);
|
|
_shadow.setFieldValue('*', 'TEXT');
|
|
_shadow.outputConnection.connect(_input.connection);
|
|
|
|
|
|
_input = this.appendValueInput('MONTHS')
|
|
.appendField(Blockly.Words['cron_builder_month'][systemLang]);
|
|
_shadow = this.workspace.newBlock('text');
|
|
_shadow.setShadow(true);
|
|
_shadow.setFieldValue('*', 'TEXT');
|
|
_shadow.outputConnection.connect(_input.connection);
|
|
|
|
_input = this.appendValueInput('DAYS')
|
|
.appendField(Blockly.Words['cron_builder_day'][systemLang]);
|
|
_shadow = this.workspace.newBlock('text');
|
|
_shadow.setShadow(true);
|
|
_shadow.setFieldValue('*', 'TEXT');
|
|
_shadow.outputConnection.connect(_input.connection);
|
|
|
|
|
|
_input = this.appendValueInput('HOURS')
|
|
.appendField(Blockly.Words['cron_builder_hour'][systemLang]);
|
|
_shadow = this.workspace.newBlock('text');
|
|
_shadow.setShadow(true);
|
|
_shadow.setFieldValue('*', 'TEXT');
|
|
_shadow.outputConnection.connect(_input.connection);
|
|
|
|
|
|
_input = this.appendValueInput('MINUTES')
|
|
.appendField(Blockly.Words['cron_builder_minutes'][systemLang]);
|
|
_shadow = this.workspace.newBlock('text');
|
|
_shadow.setShadow(true);
|
|
_shadow.setFieldValue('*', 'TEXT');
|
|
_shadow.outputConnection.connect(_input.connection);
|
|
|
|
this.appendDummyInput('WITH_SECONDS')
|
|
.appendField(Blockly.Words['cron_builder_with_seconds'][systemLang])
|
|
.appendField(new Blockly.FieldCheckbox('FALSE', function (option) {
|
|
var withSeconds = (option == true);
|
|
this.sourceBlock_.updateShape_(withSeconds);
|
|
}), 'WITH_SECONDS');
|
|
|
|
this.seconds_ = false;
|
|
this.as_line_ = false;
|
|
this.setInputsInline(this.as_line_);
|
|
this.setColour(Blockly.Trigger.HUE);
|
|
this.setOutput(true, 'String');
|
|
this.setTooltip(Blockly.Words['field_cron_tooltip'][systemLang]);
|
|
},
|
|
/**
|
|
* Create XML to represent number of text inputs.
|
|
* @return {!Element} XML storage element.
|
|
* @this Blockly.Block
|
|
*/
|
|
mutationToDom: function () {
|
|
var container = document.createElement('mutation');
|
|
container.setAttribute('seconds', this.seconds_);
|
|
container.setAttribute('as_line', this.as_line_);
|
|
return container;
|
|
},
|
|
/**
|
|
* Parse XML to restore the text inputs.
|
|
* @param {!Element} xmlElement XML storage element.
|
|
* @this Blockly.Block
|
|
*/
|
|
domToMutation: function (xmlElement) {
|
|
this.seconds_ = xmlElement.getAttribute('seconds') === 'true';
|
|
this.as_line_ = xmlElement.getAttribute('as_line') === 'true';
|
|
this.setInputsInline(this.as_line_);
|
|
this.updateShape_(this.seconds_);
|
|
},
|
|
updateShape_: function(withSeconds) {
|
|
this.seconds_ = withSeconds;
|
|
// Add or remove a statement Input.
|
|
var inputExists = this.getInput('SECONDS');
|
|
|
|
if (withSeconds) {
|
|
if (!inputExists) {
|
|
var _input = this.appendValueInput('SECONDS');
|
|
_input.appendField(Blockly.Words['cron_builder_seconds'][systemLang]);
|
|
|
|
var _shadow = this.workspace.newBlock('text');
|
|
_shadow.setShadow(true);
|
|
_shadow.setFieldValue('*', 'TEXT');
|
|
_shadow.outputConnection.connect(_input.connection);
|
|
_shadow.initSvg();
|
|
_shadow.render();
|
|
}
|
|
} else if (inputExists) {
|
|
this.removeInput('SECONDS');
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
Blockly.JavaScript['cron_builder'] = function(block) {
|
|
var dow = Blockly.JavaScript.valueToCode(block, 'DOW', Blockly.JavaScript.ORDER_ATOMIC);
|
|
var months = Blockly.JavaScript.valueToCode(block, 'MONTHS', Blockly.JavaScript.ORDER_ATOMIC);
|
|
var days = Blockly.JavaScript.valueToCode(block, 'DAYS', Blockly.JavaScript.ORDER_ATOMIC);
|
|
var hours = Blockly.JavaScript.valueToCode(block, 'HOURS', Blockly.JavaScript.ORDER_ATOMIC);
|
|
var minutes = Blockly.JavaScript.valueToCode(block, 'MINUTES', Blockly.JavaScript.ORDER_ATOMIC);
|
|
var seconds = Blockly.JavaScript.valueToCode(block, 'SECONDS', Blockly.JavaScript.ORDER_ATOMIC);
|
|
var withSeconds = block.getFieldValue('WITH_SECONDS');
|
|
|
|
var code = ((withSeconds === 'TRUE') ? seconds + '.trim() + \' \' + ' : '') + minutes + '.trim() + \' \' + ' + hours + '.trim() + \' \' + ' + days + '.trim() + \' \' + ' + months + '.trim() + \' \' + ' + dow + '.trim()';
|
|
return [code, Blockly.JavaScript.ORDER_ATOMIC]
|
|
};
|