Hello,
I'm struggling with a mutator, which is nearly finished:
But id does not work... When I add an element and try to move the obtained block, it explodes :-D
It's like it does not save child or element. If someone has an example of something similar to my problem, or if you see an evident problem on my code, that would be great!
Blockly.defineBlocksWithJsonArray(
[{
"type": "board_serial_formatCSV",
"message0": "serialize CSV %1",
"args0": [{
"type": "input_dummy"
}
],
"message1": "data %1",
"args1": [{
"type": "input_value",
"name": "DATA0",
"check": ['int', 'float', 'Number', 'Array']
}
],
"message2": "separator %1",
"args2": [{
"type": "input_value",
"name": "SEP0",
"check": "String"
}
],
"previousStatement": null,
"nextStatement": null,
"style": "board_blocks",
"helpUrl": "lien vers le wiki",
"mutator": "serial_formatCSV_mutator",
"tooltip": "serial_formatCSV_tooltip"
}, {
"type": "mutator_stack",
"message0": "stack",
"nextStatement": null,
"enableContextMenu": null,
"style": "board_blocks",
"tooltip": "%{BKY_mutator_this.stack_TOOLTIP}"
}, {
"type": "mutator_data",
"message0": "data to send",
"previousStatement": null,
"nextStatement": null,
"style": "board_blocks",
"tooltip": "%{BKY_mutator_data_TOOLTIP}"
}, {
"type": "mutator_sep",
"message0": "separator",
"previousStatement": null,
"nextStatement": null,
"style": "board_blocks",
"tooltip": "%{BKY_mutator_sep_TOOLTIP}"
}
]);
/**
* Mutator methods added to controls_if blocks.
* @mixin
* @augments Blockly.Block
* @package
* @readonly
*/
Blockly.Block.FORMATCSV_MUTATOR_MIXIN = {
dataCount_: 1,
sepCount_: 1,
totalCount_: 2,
stack_: ['d', 's'],
/**
* Don't automatically add STATEMENT_PREFIX and STATEMENT_SUFFIX to generated
* code. These will be handled manually in this block's generators.
*/
suppressPrefixSuffix: true,
/**
* Create XML to represent the number of data and separator inputs.
* @return {Element} XML storage element.
* @this {Blockly.Block}
*/
mutationToDom: function () {
if (!this.dataCount_ && !this.sepCount_) {
return null;
}
var container = Blockly.utils.xml.createElement('mutation');
if (this.dataCount_) {
container.setAttribute('attribData', this.dataCount_);
}
if (this.sepCount_) {
container.setAttribute('attribSep', this.sepCount_);
}
return container;
},
/**
* Parse XML to restore the data and separator inputs.
* @param {!Element} xmlElement XML storage element.
* @this {Blockly.Block}
*/
domToMutation: function (xmlElement) {
this.dataCount_ = parseInt(xmlElement.getAttribute('attribData'), 10) || 0;
this.sepCount_ = parseInt(xmlElement.getAttribute('attribSep'), 10) || 0;
this.totalCount_ = this.dataCount_ + this.sepCount_;
console.log(this.dataCount_);
console.log(this.sepCount_);
console.log(this.totalCount_);
this.rebuildShape_();
},
/**
* 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('mutator_stack');
containerBlock.initSvg();
var connection = containerBlock.nextConnection;
for (var i = 0; i < this.totalCount_; i++) {
if (this.stack_[i] == 's') {
var sepBlock = workspace.newBlock('mutator_sep');
sepBlock.initSvg();
connection.connect(sepBlock.previousConnection);
connection = sepBlock.nextConnection;
} else if (this.stack_[i] == 'd') {
var dataBlock = workspace.newBlock('mutator_data');
dataBlock.initSvg();
connection.connect(dataBlock.previousConnection);
connection = dataBlock.nextConnection;
}
}
console.log('stack ' + this.stack_);
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 clauseBlock = containerBlock.nextConnection.targetBlock();
// Count number of inputs.
this.dataCount_ = 0;
this.sepCount_ = 0;
this.totalCount_ = 0;
var dataConnections = [null];
var separatorConnections = [null];
while (clauseBlock && !clauseBlock.isInsertionMarker()) {
switch (clauseBlock.type) {
case 'mutator_data':
this.stack_[this.totalCount_] = 'd';
this.dataCount_++;
this.totalCount_++;
dataConnections.push(clauseBlock.valueConnection_);
clauseBlock = clauseBlock.nextConnection && clauseBlock.nextConnection.targetBlock();
break;
case 'mutator_sep':
this.stack_[this.totalCount_] = 's';
this.sepCount_++;
this.totalCount_++;
separatorConnections.push(clauseBlock.valueConnection_);
clauseBlock = clauseBlock.nextConnection && clauseBlock.nextConnection.targetBlock();
break;
default:
throw TypeError('Unknown block type: ' + clauseBlock.type);
}
}
console.log('step 4');
this.updateShape_();
// Reconnect any child blocks.
this.reconnectChildBlocks_(dataConnections, separatorConnections);
},
/**
* Store pointers to any connected child blocks.
* @param {!Blockly.Block} containerBlock Root block in mutator.
* @this {Blockly.Block}
*/
saveConnections: function (containerBlock) {
var clauseBlock = containerBlock.nextConnection.targetBlock();
var i = 0;
var j = 0;
while (clauseBlock) {
switch (clauseBlock.type) {
case 'mutator_data':
var input = this.getInput('DATA' + i);
i++;
break;
case 'mutator_sep':
var input = this.getInput('SEP' + j);
j++;
break;
default:
throw TypeError('Unknown block type: ' + clauseBlock.type);
}
clauseBlock.valueConnection_ = input && input.connection.targetConnection;
console.log(clauseBlock.valueConnection_);
clauseBlock = clauseBlock.nextConnection &&
clauseBlock.nextConnection.targetBlock();
}
console.log('i' + i);
console.log('j' + j);
},
/**
* Reconstructs the block with all child blocks attached.
* @this {Blockly.Block}
*/
rebuildShape_: function () {
var valueConnections = [null];
var i = 0;
var j = 0;
var k = 0;
while (i < this.totalCount_) {
switch (this.stack_[i]) {
case 'd':
var inputData = this.getInput('DATA' + j);
valueConnections.push(inputData.connection.targetConnection);
j++;
break;
case 's':
var inputSep = this.getInput('SEP' + k);
valueConnections.push(inputSep.connection.targetConnection);
k++;
break;
default:
throw TypeError('Unknown block type: ' + clauseBlock.type);
}
i++;
}
// console.log(valueConnections);
this.updateShape_();
this.reconnectChildBlocks_(valueConnections);
},
/**
* Modify this block to have the correct number of inputs.
* @this {Blockly.Block}
* @private
*/
updateShape_: function () {
// Delete everything.
var i = 0;
while (this.getInput('DATA' + i)) {
this.removeInput('DATA' + i);
i++;
}
var i = 0;
while (this.getInput('SEP' + i)) {
this.removeInput('SEP' + i);
i++;
}
console
// Rebuild block.
var j = 0;
var k = 0;
for (i = 0; i < this.totalCount_; i++) {
switch (this.stack_[i]) {
case 'd':
this.appendValueInput('DATA' + j)
.setCheck('Number')
.appendField("new data");
j++;
break;
case 's':
this.appendValueInput('SEP' + k)
.setCheck('String')
.appendField("data separator");
k++;
break;
}
}
},
/**
* Reconnects child blocks.
* @param {!Array.<?Blockly.RenderedConnection>} dataConnections List of
* value connections for 'if' input.
* @param {!Array.<?Blockly.RenderedConnection>} separatorConnections List of
* statement connections for 'sep' input.
* @param {?Blockly.RenderedConnection} elseSeparatorConnection Statement
* connection for else input.
* @this {Blockly.Block}
*/
reconnectChildBlocks_: function (valueConnections) {
var j = 0;
var k = 0;
for (var i = 0; i < this.totalCount_; i++) {
switch (this.stack_[i]) {
case 'd':
Blockly.Mutator.reconnect(valueConnections[i], this, 'DATA' + j);
j++;
break;
case 's':
Blockly.Mutator.reconnect(valueConnections[i], this, 'SEP' + k);
k++
break;
}
}
}
};
Blockly.Extensions.registerMutator('serial_formatCSV_mutator',
Blockly.Block.FORMATCSV_MUTATOR_MIXIN, null, ['mutator_data', 'mutator_sep']);
Many thanks!