feat: upgrade block defs to have JSO serialization hooks (#5329)

* Respect nulls from blocks.save

* Upgrade list blocks to use JSO serialization

* Upgrade logic blocks to use JSO serialization

* Upgrade math blocks to use JSO serialization

* Upgrade text blocks to use JSO serialization

* Upgrade procedure blocks to use JSO serialization

* Add more mutator tests

* Fix firing enabled events

* PR Comments
This commit is contained in:
Beka Westberg
2021-08-12 15:53:28 +00:00
committed by alschmiedt
parent bd77b4ad3d
commit ee78b41987
9 changed files with 293 additions and 13 deletions

View File

@@ -131,6 +131,7 @@ Blockly.Blocks['lists_create_with'] = {
},
/**
* Create XML to represent list inputs.
* Backwards compatible serialization implementation.
* @return {!Element} XML storage element.
* @this {Blockly.Block}
*/
@@ -141,6 +142,7 @@ Blockly.Blocks['lists_create_with'] = {
},
/**
* Parse XML to restore the list inputs.
* Backwards compatible serialization implementation.
* @param {!Element} xmlElement XML storage element.
* @this {Blockly.Block}
*/
@@ -148,6 +150,23 @@ Blockly.Blocks['lists_create_with'] = {
this.itemCount_ = parseInt(xmlElement.getAttribute('items'), 10);
this.updateShape_();
},
/**
* Returns the state of this block as a JSON serializable object.
* @return {{itemCount: number}} The state of this block, ie the item count.
*/
saveExtraState: function() {
return {
'itemCount': this.itemCount_,
};
},
/**
* Applies the given state to this block.
* @param {*} state The state to apply to this block, ie the item count.
*/
loadExtraState: function(state) {
this.itemCount_ = state['itemCount'];
this.updateShape_();
},
/**
* Populate the mutator's dialog with this block's components.
* @param {!Blockly.Workspace} workspace Mutator's workspace.
@@ -424,6 +443,12 @@ Blockly.Blocks['lists_getIndex'] = {
var isAt = (xmlElement.getAttribute('at') != 'false');
this.updateAt_(isAt);
},
// This block does not need JSO serialization hooks (saveExtraState and
// loadExtraState) because the state of this object is already encoded in the
// dropdown values.
// XML hooks are kept for backwards compatibility.
/**
* Switch between a value block and a statement block.
* @param {boolean} newStatement True if the block should be a statement.
@@ -584,6 +609,12 @@ Blockly.Blocks['lists_setIndex'] = {
var isAt = (xmlElement.getAttribute('at') != 'false');
this.updateAt_(isAt);
},
// This block does not need JSO serialization hooks (saveExtraState and
// loadExtraState) because the state of this object is already encoded in the
// dropdown values.
// XML hooks are kept for backwards compatibility.
/**
* Create or delete an input for the numeric index.
* @param {boolean} isAt True if the input should exist.
@@ -684,6 +715,12 @@ Blockly.Blocks['lists_getSublist'] = {
this.updateAt_(1, isAt1);
this.updateAt_(2, isAt2);
},
// This block does not need JSO serialization hooks (saveExtraState and
// loadExtraState) because the state of this object is already encoded in the
// dropdown values.
// XML hooks are kept for backwards compatibility.
/**
* Create or delete an input for a numeric index.
* This block has two such inputs, independent of each other.
@@ -857,5 +894,10 @@ Blockly.Blocks['lists_split'] = {
*/
domToMutation: function(xmlElement) {
this.updateType_(xmlElement.getAttribute('mode'));
}
},
// This block does not need JSO serialization hooks (saveExtraState and
// loadExtraState) because the state of this object is already encoded in the
// dropdown values.
// XML hooks are kept for backwards compatibility.
};

View File

@@ -303,6 +303,7 @@ Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN = {
/**
* Create XML to represent the number of else-if and else inputs.
* Backwards compatible serialization implementation.
* @return {Element} XML storage element.
* @this {Blockly.Block}
*/
@@ -321,6 +322,7 @@ Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN = {
},
/**
* Parse XML to restore the else-if and else inputs.
* Backwards compatible serialization implementation.
* @param {!Element} xmlElement XML storage element.
* @this {Blockly.Block}
*/
@@ -329,6 +331,34 @@ Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN = {
this.elseCount_ = parseInt(xmlElement.getAttribute('else'), 10) || 0;
this.rebuildShape_();
},
/**
* Returns the state of this block as a JSON serializable object.
* @return {?{elseIfCount: (number|undefined), haseElse: (boolean|undefined)}}
* The state of this block, ie the else if count and else state.
*/
saveExtraState: function() {
if (!this.elseifCount_ && !this.elseCount_) {
return null;
}
var state = Object.create(null);
if (this.elseifCount_) {
state['elseIfCount'] = this.elseifCount_;
}
if (this.elseCount_) {
state['hasElse'] = true;
}
return state;
},
/**
* Applies the given state to this block.
* @param {*} state The state to apply to this block, ie the else if count and
* else state.
*/
loadExtraState: function(state) {
this.elseifCount_ = state['elseIfCount'] || 0;
this.elseCount_ = state['hasElse'] ? 1 : 0;
this.updateShape_();
},
/**
* Populate the mutator's dialog with this block's components.
* @param {!Blockly.Workspace} workspace Mutator's workspace.

View File

@@ -446,6 +446,7 @@ Blockly.Extensions.register('math_op_tooltip',
Blockly.Constants.Math.IS_DIVISIBLEBY_MUTATOR_MIXIN = {
/**
* Create XML to represent whether the 'divisorInput' should be present.
* Backwards compatible serialization implementation.
* @return {!Element} XML storage element.
* @this {Blockly.Block}
*/
@@ -457,6 +458,7 @@ Blockly.Constants.Math.IS_DIVISIBLEBY_MUTATOR_MIXIN = {
},
/**
* Parse XML to restore the 'divisorInput'.
* Backwards compatible serialization implementation.
* @param {!Element} xmlElement XML storage element.
* @this {Blockly.Block}
*/
@@ -464,6 +466,12 @@ Blockly.Constants.Math.IS_DIVISIBLEBY_MUTATOR_MIXIN = {
var divisorInput = (xmlElement.getAttribute('divisor_input') == 'true');
this.updateShape_(divisorInput);
},
// This block does not need JSO serialization hooks (saveExtraState and
// loadExtraState) because the state of this object is already encoded in the
// dropdown values.
// XML hooks are kept for backwards compatibility.
/**
* Modify this block to have (or not have) an input for 'is divisible by'.
* @param {boolean} divisorInput True if this block has a divisor input.
@@ -531,6 +539,7 @@ Blockly.Constants.Math.LIST_MODES_MUTATOR_MIXIN = {
},
/**
* Create XML to represent the output type.
* Backwards compatible serialization implementation.
* @return {!Element} XML storage element.
* @this {Blockly.Block}
*/
@@ -541,12 +550,18 @@ Blockly.Constants.Math.LIST_MODES_MUTATOR_MIXIN = {
},
/**
* Parse XML to restore the output type.
* Backwards compatible serialization implementation.
* @param {!Element} xmlElement XML storage element.
* @this {Blockly.Block}
*/
domToMutation: function(xmlElement) {
this.updateType_(xmlElement.getAttribute('op'));
}
},
// This block does not need JSO serialization hooks (saveExtraState and
// loadExtraState) because the state of this object is already encoded in the
// dropdown values.
// XML hooks are kept for backwards compatibility.
};
/**

View File

@@ -95,6 +95,7 @@ Blockly.Blocks['procedures_defnoreturn'] = {
},
/**
* Create XML to represent the argument inputs.
* Backwards compatible serialization implementation.
* @param {boolean=} opt_paramIds If true include the IDs of the parameter
* quarks. Used by Blockly.Procedures.mutateCallers for reconnection.
* @return {!Element} XML storage element.
@@ -124,6 +125,7 @@ Blockly.Blocks['procedures_defnoreturn'] = {
},
/**
* Parse XML to restore the argument inputs.
* Backwards compatible serialization implementation.
* @param {!Element} xmlElement XML storage element.
* @this {Blockly.Block}
*/
@@ -150,6 +152,54 @@ Blockly.Blocks['procedures_defnoreturn'] = {
// Show or hide the statement input.
this.setStatements_(xmlElement.getAttribute('statements') !== 'false');
},
/**
* Returns the state of this block as a JSON serializable object.
* @return {?{params: (!Array<{name: string, id: string}>|undefined),
* hasStatements: (boolean|undefined)}} The state of this block, eg the
* parameters and statements.
*/
saveExtraState: function() {
if (!this.argumentVarModels_.length && this.hasStatements_) {
return null;
}
var state = Object.create(null);
if (this.argumentVarModels_.length) {
state['params'] = [];
for (var i = 0; i < this.argumentVarModels_.length; i++) {
state['params'].push({
// We don't need to serialize the name, but just in case we decide
// to separate params from variables.
'name': this.argumentVarModels_[i].name,
'id': this.argumentVarModels_[i].getId()
});
}
}
if (!this.hasStatements_) {
state['hasStatements'] = false;
}
return state;
},
/**
* Applies the given state to this block.
* @param {*} state The state to apply to this block, eg the parameters and
* statements.
*/
loadExtraState: function(state) {
this.arguments_ = [];
this.argumentVarModels_ = [];
if (state['params']) {
for (var i = 0; i < state['params'].length; i++) {
var param = state['params'][i];
var variable = Blockly.Variables.getOrCreateVariablePackage(
this.workspace, param['id'], param['name'], '');
this.arguments_.push(variable.name);
this.argumentVarModels_.push(variable);
}
}
this.updateParams_();
Blockly.Procedures.mutateCallers(this);
this.setStatements_(state['hasStatements'] === false ? false : true);
},
/**
* Populate the mutator's dialog with this block's components.
* @param {!Blockly.Workspace} workspace Mutator's workspace.
@@ -436,6 +486,8 @@ Blockly.Blocks['procedures_defreturn'] = {
updateParams_: Blockly.Blocks['procedures_defnoreturn'].updateParams_,
mutationToDom: Blockly.Blocks['procedures_defnoreturn'].mutationToDom,
domToMutation: Blockly.Blocks['procedures_defnoreturn'].domToMutation,
saveExtraState: Blockly.Blocks['procedures_defnoreturn'].saveExtraState,
loadExtraState: Blockly.Blocks['procedures_defnoreturn'].loadExtraState,
decompose: Blockly.Blocks['procedures_defnoreturn'].decompose,
compose: Blockly.Blocks['procedures_defnoreturn'].compose,
/**
@@ -776,6 +828,7 @@ Blockly.Blocks['procedures_callnoreturn'] = {
},
/**
* Create XML to represent the (non-editable) name and arguments.
* Backwards compatible serialization implementation.
* @return {!Element} XML storage element.
* @this {Blockly.Block}
*/
@@ -791,6 +844,7 @@ Blockly.Blocks['procedures_callnoreturn'] = {
},
/**
* Parse XML to restore the (non-editable) name and parameters.
* Backwards compatible serialization implementation.
* @param {!Element} xmlElement XML storage element.
* @this {Blockly.Block}
*/
@@ -807,6 +861,34 @@ Blockly.Blocks['procedures_callnoreturn'] = {
}
this.setProcedureParameters_(args, paramIds);
},
/**
* Returns the state of this block as a JSON serializable object.
* @return {{name: string, params:(!Array<string>|undefined)}} The state of
* this block, ie the params and procedure name.
*/
saveExtraState: function() {
var state = Object.create(null);
state['name'] = this.getProcedureCall();
if (this.arguments_.length) {
state['params'] = this.arguments_;
}
return state;
},
/**
* Applies the given state to this block.
* @param {*} state The state to apply to this block, ie the params and
* procedure name.
*/
loadExtraState: function(state) {
this.renameProcedure(this.getProcedureCall(), state['name']);
const params = state['params'];
if (params) {
const ids = [];
ids.length = params.length;
ids.fill(null);
this.setProcedureParameters_(params, ids);
}
},
/**
* Return all variables referenced by this block.
* @return {!Array<string>} List of variable names.
@@ -975,6 +1057,8 @@ Blockly.Blocks['procedures_callreturn'] = {
updateShape_: Blockly.Blocks['procedures_callnoreturn'].updateShape_,
mutationToDom: Blockly.Blocks['procedures_callnoreturn'].mutationToDom,
domToMutation: Blockly.Blocks['procedures_callnoreturn'].domToMutation,
saveExtraState: Blockly.Blocks['procedures_callnoreturn'].saveExtraState,
loadExtraState: Blockly.Blocks['procedures_callnoreturn'].loadExtraState,
getVars: Blockly.Blocks['procedures_callnoreturn'].getVars,
getVarModels: Blockly.Blocks['procedures_callnoreturn'].getVarModels,
onchange: Blockly.Blocks['procedures_callnoreturn'].onchange,
@@ -1026,6 +1110,12 @@ Blockly.Blocks['procedures_ifreturn'] = {
.appendField(Blockly.Msg['PROCEDURES_DEFRETURN_RETURN']);
}
},
// This block does not need JSO serialization hooks (saveExtraState and
// loadExtraState) because the state of this block is already encoded in the
// block's position in the workspace.
// XML hooks are kept for backwards compatibility.
/**
* Called whenever anything on the workspace changes.
* Add warning if this flow block is not nested inside a loop.
@@ -1033,7 +1123,7 @@ Blockly.Blocks['procedures_ifreturn'] = {
* @this {Blockly.Block}
*/
onchange: function(_e) {
if (!this.workspace.isDragging || this.workspace.isDragging()) {
if (this.workspace.isDragging && this.workspace.isDragging()) {
return; // Don't change state at the start of a drag.
}
var legal = false;

View File

@@ -261,6 +261,7 @@ Blockly.Blocks['text_getSubstring'] = {
},
/**
* Create XML to represent whether there are 'AT' inputs.
* Backwards compatible serialization implementation.
* @return {!Element} XML storage element.
* @this {Blockly.Block}
*/
@@ -274,6 +275,7 @@ Blockly.Blocks['text_getSubstring'] = {
},
/**
* Parse XML to restore the 'AT' inputs.
* Backwards compatible serialization implementation.
* @param {!Element} xmlElement XML storage element.
* @this {Blockly.Block}
*/
@@ -283,6 +285,12 @@ Blockly.Blocks['text_getSubstring'] = {
this.updateAt_(1, isAt1);
this.updateAt_(2, isAt2);
},
// This block does not need JSO serialization hooks (saveExtraState and
// loadExtraState) because the state of this object is already encoded in the
// dropdown values.
// XML hooks are kept for backwards compatibility.
/**
* Create or delete an input for a numeric index.
* This block has two such inputs, independent of each other.
@@ -441,6 +449,7 @@ Blockly.Blocks['text_prompt_ext'] = {
},
/**
* Create XML to represent the output type.
* Backwards compatible serialization implementation.
* @return {!Element} XML storage element.
* @this {Blockly.Block}
*/
@@ -451,12 +460,18 @@ Blockly.Blocks['text_prompt_ext'] = {
},
/**
* Parse XML to restore the output type.
* Backwards compatible serialization implementation.
* @param {!Element} xmlElement XML storage element.
* @this {Blockly.Block}
*/
domToMutation: function(xmlElement) {
this.updateType_(xmlElement.getAttribute('type'));
}
},
// This block does not need JSO serialization hooks (saveExtraState and
// loadExtraState) because the state of this object is already encoded in the
// dropdown values.
// XML hooks are kept for backwards compatibility.
};
Blockly.Blocks['text_prompt'] = {
@@ -678,6 +693,7 @@ Blockly.Constants.Text.TEXT_QUOTES_EXTENSION = function() {
Blockly.Constants.Text.TEXT_JOIN_MUTATOR_MIXIN = {
/**
* Create XML to represent number of text inputs.
* Backwards compatible serialization implementation.
* @return {!Element} XML storage element.
* @this {Blockly.Block}
*/
@@ -688,6 +704,7 @@ Blockly.Constants.Text.TEXT_JOIN_MUTATOR_MIXIN = {
},
/**
* Parse XML to restore the text inputs.
* Backwards compatible serialization implementation.
* @param {!Element} xmlElement XML storage element.
* @this {Blockly.Block}
*/
@@ -695,6 +712,23 @@ Blockly.Constants.Text.TEXT_JOIN_MUTATOR_MIXIN = {
this.itemCount_ = parseInt(xmlElement.getAttribute('items'), 10);
this.updateShape_();
},
/**
* Returns the state of this block as a JSON serializable object.
* @return {{itemCount: number}} The state of this block, ie the item count.
*/
saveExtraState: function() {
return {
'itemCount': this.itemCount_,
};
},
/**
* Applies the given state to this block.
* @param {*} state The state to apply to this block, ie the item count.
*/
loadExtraState: function(state) {
this.itemCount_ = state['itemCount'];
this.updateShape_();
},
/**
* Populate the mutator's dialog with this block's components.
* @param {!Blockly.Workspace} workspace Mutator's workspace.
@@ -829,6 +863,7 @@ Blockly.Constants.Text.TEXT_INDEXOF_TOOLTIP_EXTENSION = function() {
Blockly.Constants.Text.TEXT_CHARAT_MUTATOR_MIXIN = {
/**
* Create XML to represent whether there is an 'AT' input.
* Backwards compatible serialization implementation.
* @return {!Element} XML storage element.
* @this {Blockly.Block}
*/
@@ -839,6 +874,7 @@ Blockly.Constants.Text.TEXT_CHARAT_MUTATOR_MIXIN = {
},
/**
* Parse XML to restore the 'AT' input.
* Backwards compatible serialization implementation.
* @param {!Element} xmlElement XML storage element.
* @this {Blockly.Block}
*/
@@ -848,6 +884,12 @@ Blockly.Constants.Text.TEXT_CHARAT_MUTATOR_MIXIN = {
var isAt = (xmlElement.getAttribute('at') != 'false');
this.updateAt_(isAt);
},
// This block does not need JSO serialization hooks (saveExtraState and
// loadExtraState) because the state of this object is already encoded in the
// dropdown values.
// XML hooks are kept for backwards compatibility.
/**
* Create or delete an input for the numeric index.
* @param {boolean} isAt True if the input should exist.

View File

@@ -1335,9 +1335,10 @@ Block.prototype.isEnabled = function() {
*/
Block.prototype.setEnabled = function(enabled) {
if (this.isEnabled() != enabled) {
Events.fire(new (Events.get(Events.BLOCK_CHANGE))(
this, 'disabled', null, this.disabled, !enabled));
const oldValue = this.disabled;
this.disabled = !enabled;
Events.fire(new (Events.get(Events.BLOCK_CHANGE))(
this, 'disabled', null, oldValue, !enabled));
}
};

View File

@@ -41,8 +41,7 @@ const save = function(workspace) {
const blockStates = [];
for (let block of workspace.getTopBlocks(false)) {
const blockState =
blocks.save(block, {addCoordinates: true});
const blockState = blocks.save(block, {addCoordinates: true});
if (blockState) {
blockStates.push(blockState);
}

View File

@@ -1,10 +1,10 @@
goog.addDependency('../../blocks/colour.js', ['Blockly.Blocks.colour', 'Blockly.Constants.Colour'], ['Blockly', 'Blockly.Blocks', 'Blockly.FieldColour', 'Blockly.FieldLabel']);
goog.addDependency('../../blocks/lists.js', ['Blockly.Constants.Lists'], ['Blockly', 'Blockly.Blocks', 'Blockly.FieldDropdown', 'Blockly.FieldLabel', 'Blockly.Mutator']);
goog.addDependency('../../blocks/lists.js', ['Blockly.Constants.Lists'], ['Blockly', 'Blockly.Blocks', 'Blockly.FieldDropdown', 'Blockly.FieldLabel', 'Blockly.Mutator'], {'lang': 'es5'});
goog.addDependency('../../blocks/logic.js', ['Blockly.Blocks.logic', 'Blockly.Constants.Logic'], ['Blockly', 'Blockly.Blocks', 'Blockly.FieldDropdown', 'Blockly.FieldLabel', 'Blockly.Mutator']);
goog.addDependency('../../blocks/loops.js', ['Blockly.Blocks.loops', 'Blockly.Constants.Loops'], ['Blockly', 'Blockly.Blocks', 'Blockly.FieldDropdown', 'Blockly.FieldLabel', 'Blockly.FieldNumber', 'Blockly.FieldVariable', 'Blockly.Warning']);
goog.addDependency('../../blocks/math.js', ['Blockly.Blocks.math', 'Blockly.Constants.Math'], ['Blockly', 'Blockly.Blocks', 'Blockly.FieldDropdown', 'Blockly.FieldLabel', 'Blockly.FieldNumber', 'Blockly.FieldVariable']);
goog.addDependency('../../blocks/procedures.js', ['Blockly.Blocks.procedures'], ['Blockly', 'Blockly.Blocks', 'Blockly.Comment', 'Blockly.FieldCheckbox', 'Blockly.FieldLabel', 'Blockly.FieldTextInput', 'Blockly.Mutator', 'Blockly.Warning'], {'lang': 'es5'});
goog.addDependency('../../blocks/text.js', ['Blockly.Blocks.texts', 'Blockly.Constants.Text'], ['Blockly', 'Blockly.Blocks', 'Blockly.FieldDropdown', 'Blockly.FieldImage', 'Blockly.FieldMultilineInput', 'Blockly.FieldTextInput', 'Blockly.FieldVariable', 'Blockly.Mutator']);
goog.addDependency('../../blocks/math.js', ['Blockly.Blocks.math', 'Blockly.Constants.Math'], ['Blockly', 'Blockly.Blocks', 'Blockly.FieldDropdown', 'Blockly.FieldLabel', 'Blockly.FieldNumber', 'Blockly.FieldVariable'], {'lang': 'es5'});
goog.addDependency('../../blocks/procedures.js', ['Blockly.Blocks.procedures'], ['Blockly', 'Blockly.Blocks', 'Blockly.Comment', 'Blockly.FieldCheckbox', 'Blockly.FieldLabel', 'Blockly.FieldTextInput', 'Blockly.Mutator', 'Blockly.Warning'], {'lang': 'es6'});
goog.addDependency('../../blocks/text.js', ['Blockly.Blocks.texts', 'Blockly.Constants.Text'], ['Blockly', 'Blockly.Blocks', 'Blockly.FieldDropdown', 'Blockly.FieldImage', 'Blockly.FieldMultilineInput', 'Blockly.FieldTextInput', 'Blockly.FieldVariable', 'Blockly.Mutator'], {'lang': 'es5'});
goog.addDependency('../../blocks/variables.js', ['Blockly.Blocks.variables', 'Blockly.Constants.Variables'], ['Blockly', 'Blockly.Blocks', 'Blockly.FieldLabel', 'Blockly.FieldVariable']);
goog.addDependency('../../blocks/variables_dynamic.js', ['Blockly.Constants.VariablesDynamic'], ['Blockly', 'Blockly.Blocks', 'Blockly.FieldLabel', 'Blockly.FieldVariable']);
goog.addDependency('../../core/block.js', ['Blockly.Block'], ['Blockly.ASTNode', 'Blockly.Blocks', 'Blockly.Connection', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Extensions', 'Blockly.Input', 'Blockly.Tooltip', 'Blockly.common', 'Blockly.connectionTypes', 'Blockly.constants', 'Blockly.fieldRegistry', 'Blockly.inputTypes', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Size', 'Blockly.utils.idGenerator', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});

View File

@@ -1313,6 +1313,30 @@ Serializer.Connections.testSuites = [
];
Serializer.Mutations = new SerializerTestSuite('Mutations');
Serializer.Mutations.ListGetIndex = new SerializerTestCase('ListGetIndex',
'<xml xmlns="https://developers.google.com/blockly/xml">' +
'<block type="lists_getIndex" id="id" x="42" y="42">' +
'<mutation statement="true" at="false"></mutation>' +
'<field name="MODE">REMOVE</field>' +
'<field name="WHERE">LAST</field>' +
'</block>' +
'</xml>');
Serializer.Mutations.ListSetIndex = new SerializerTestCase('ListSetIndex',
'<xml xmlns="https://developers.google.com/blockly/xml">' +
'<block type="lists_setIndex" id="id" x="42" y="42">' +
'<mutation at="false"></mutation>' +
'<field name="MODE">SET</field>' +
'<field name="WHERE">LAST</field>' +
'</block>' +
'</xml>');
Serializer.Mutations.ListGetSublist = new SerializerTestCase('ListGetSublist',
'<xml xmlns="https://developers.google.com/blockly/xml">' +
'<block type="lists_getSublist" id="id" x="42" y="42">' +
'<mutation at1="false" at2="false"></mutation>' +
'<field name="WHERE1">FIRST</field>' +
'<field name="WHERE2">LAST</field>' +
'</block>' +
'</xml>');
Serializer.Mutations.MathNumberProperty = new SerializerTestCase(
'MathNumberProperty',
'<xml xmlns="https://developers.google.com/blockly/xml">' +
@@ -1371,6 +1395,9 @@ Serializer.Mutations.TextPrompt = new SerializerTestCase(
'</block>' +
'</xml>');
Serializer.Mutations.testCases = [
Serializer.Mutations.ListGetIndex,
Serializer.Mutations.ListSetIndex,
Serializer.Mutations.ListGetSublist,
Serializer.Mutations.MathNumberProperty,
Serializer.Mutations.MathOnList,
Serializer.Mutations.TextJoin,
@@ -1621,10 +1648,45 @@ Serializer.Mutations.Procedure.NoStatements = new SerializerTestCase(
'<field name="NAME">do something</field>' +
'</block>' +
'</xml>');
Serializer.Mutations.Procedure.IfReturn = new SerializerTestCase(
'IfReturn',
'<xml xmlns="https://developers.google.com/blockly/xml">' +
'<block type="procedures_defnoreturn" id="id" x="42" y="42">' +
'<field name="NAME">do something</field>' +
'<statement name="STACK">' +
'<block type="procedures_ifreturn" id="id2">' +
'<mutation value="0"></mutation>' +
'</block>' +
'</statement>' +
'</block>' +
'</xml>');
Serializer.Mutations.Procedure.Caller = new SerializerTestCase(
'Caller',
'<xml xmlns="https://developers.google.com/blockly/xml">' +
'<variables>' +
'<variable id="aaaaaaaaaaaaaaaaaaaa">x</variable>' +
'<variable id="bbbbbbbbbbbbbbbbbbbb">y</variable>' +
'</variables>' +
'<block type="procedures_defreturn" id="id2*****************" x="42" y="42">' +
'<mutation>' +
'<arg name="x" varid="aaaaaaaaaaaaaaaaaaaa"></arg>' +
'<arg name="y" varid="bbbbbbbbbbbbbbbbbbbb"></arg>' +
'</mutation>' +
'<field name="NAME">do something</field>' +
'</block>' +
'<block type="procedures_callreturn" id="id******************" x="52" y="52">' +
'<mutation name="do something">' +
'<arg name="x"></arg>' +
'<arg name="y"></arg>' +
'</mutation>' +
'</block>' +
'</xml>');
Serializer.Mutations.Procedure.testCases = [
Serializer.Mutations.Procedure.NoMutation,
Serializer.Mutations.Procedure.Variables,
Serializer.Mutations.Procedure.NoStatements,
Serializer.Mutations.Procedure.IfReturn,
Serializer.Mutations.Procedure.Caller,
];
Serializer.Mutations.Procedure.Names = new SerializerTestSuite('Names');
@@ -1773,5 +1835,4 @@ var runSerializerTestSuite = (serializer, deserializer, testSuite) => {
runSerializerTestSuite(null, null, Serializer);
Serializer.Icons.skip = true;
Serializer.Mutations.skip = true;
runSerializerTestSuite(state => state, state => state, Serializer);