mirror of
https://github.com/google/blockly.git
synced 2026-01-06 08:30:13 +01:00
Merge pull request #952 from rachel-fenichel/feature/if_else_update
Use mutator extension for controls_if block
This commit is contained in:
@@ -86,7 +86,8 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
||||
"nextStatement": null,
|
||||
"colour": "%{BKY_LOGIC_HUE}",
|
||||
"helpUrl": "%{BKY_CONTROLS_IF_HELPURL}",
|
||||
"extensions": ["controls_if_mutator"]
|
||||
"mutator": "controls_if_mutator",
|
||||
"extensions": ["controls_if_tooltip"]
|
||||
},
|
||||
// If/else block that does not use a mutator.
|
||||
{
|
||||
@@ -457,15 +458,16 @@ Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN = {
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Extensions.registerMutator('controls_if_mutator',
|
||||
Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN, null,
|
||||
['controls_if_elseif', 'controls_if_else']);
|
||||
/**
|
||||
* "controls_if" extension function. Adds mutator, shape updating methods, and
|
||||
* dynamic tooltip to "controls_if" blocks.
|
||||
* @this Blockly.Block
|
||||
* @package
|
||||
*/
|
||||
Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_EXTENSION = function() {
|
||||
this.setMutator(new Blockly.Mutator(['controls_if_elseif', 'controls_if_else']));
|
||||
this.mixin(Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN);
|
||||
Blockly.Constants.Logic.CONTROLS_IF_TOOLTIP_EXTENSION = function() {
|
||||
|
||||
this.setTooltip(function() {
|
||||
if (!this.elseifCount_ && !this.elseCount_) {
|
||||
@@ -481,11 +483,11 @@ Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_EXTENSION = function() {
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Blockly.Extensions.register('controls_if_mutator',
|
||||
Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_EXTENSION);
|
||||
Blockly.Extensions.register('controls_if_tooltip',
|
||||
Blockly.Constants.Logic.CONTROLS_IF_TOOLTIP_EXTENSION);
|
||||
|
||||
/**
|
||||
* Corrects the logic_compate dropdown label with respect to language direction.
|
||||
* Corrects the logic_compare dropdown label with respect to language direction.
|
||||
* @this Blockly.Block
|
||||
* @package
|
||||
*/
|
||||
@@ -513,7 +515,7 @@ Blockly.Constants.Logic.fixLogicCompareRtlOpLabels =
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds dynamic type validation for the left and right sides of a logic_compate block.
|
||||
* Adds dynamic type validation for the left and right sides of a logic_compare block.
|
||||
* @mixin
|
||||
* @augments Blockly.Block
|
||||
* @package
|
||||
|
||||
@@ -207,7 +207,7 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
||||
"output": "Boolean",
|
||||
"colour": "%{BKY_MATH_HUE}",
|
||||
"tooltip": "%{BKY_MATH_IS_TOOLTIP}",
|
||||
"extensions": ["math_is_divisibleby_mutator"]
|
||||
"mutator": "math_is_divisibleby_mutator"
|
||||
},
|
||||
|
||||
// Block for adding to a variable in place.
|
||||
@@ -288,7 +288,8 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
||||
"output": "Number",
|
||||
"colour": "%{BKY_MATH_HUE}",
|
||||
"helpUrl": "%{BKY_MATH_ONLIST_HELPURL}",
|
||||
"extensions": ["math_op_tooltip", "math_modes_of_list_mutator"]
|
||||
"mutator": "math_modes_of_list_mutator",
|
||||
"extensions": ["math_op_tooltip"]
|
||||
},
|
||||
|
||||
// Block for remainder of a division.
|
||||
@@ -480,14 +481,14 @@ Blockly.Constants.Math.IS_DIVISIBLEBY_MUTATOR_MIXIN = {
|
||||
* @package
|
||||
*/
|
||||
Blockly.Constants.Math.IS_DIVISIBLE_MUTATOR_EXTENSION = function() {
|
||||
this.mixin(Blockly.Constants.Math.IS_DIVISIBLEBY_MUTATOR_MIXIN);
|
||||
this.getField('PROPERTY').setValidator(function(option) {
|
||||
var divisorInput = (option == 'DIVISIBLE_BY');
|
||||
this.sourceBlock_.updateShape_(divisorInput);
|
||||
});
|
||||
};
|
||||
|
||||
Blockly.Extensions.register('math_is_divisibleby_mutator',
|
||||
Blockly.Extensions.registerMutator('math_is_divisibleby_mutator',
|
||||
Blockly.Constants.Math.IS_DIVISIBLEBY_MUTATOR_MIXIN,
|
||||
Blockly.Constants.Math.IS_DIVISIBLE_MUTATOR_EXTENSION);
|
||||
|
||||
/**
|
||||
@@ -555,11 +556,11 @@ Blockly.Constants.Math.LIST_MODES_MUTATOR_MIXIN = {
|
||||
* @package
|
||||
*/
|
||||
Blockly.Constants.Math.LIST_MODES_MUTATOR_EXTENSION = function() {
|
||||
this.mixin(Blockly.Constants.Math.LIST_MODES_MUTATOR_MIXIN);
|
||||
this.getField('OP').setValidator(function(newOp) {
|
||||
this.updateType_(newOp);
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Blockly.Extensions.register('math_modes_of_list_mutator',
|
||||
Blockly.Extensions.registerMutator('math_modes_of_list_mutator',
|
||||
Blockly.Constants.Math.LIST_MODES_MUTATOR_MIXIN,
|
||||
Blockly.Constants.Math.LIST_MODES_MUTATOR_EXTENSION);
|
||||
|
||||
@@ -984,6 +984,7 @@ Blockly.Block.prototype.appendDummyInput = function(opt_name) {
|
||||
* @param {!Object} json Structured data describing the block.
|
||||
*/
|
||||
Blockly.Block.prototype.jsonInit = function(json) {
|
||||
|
||||
// Validate inputs.
|
||||
goog.asserts.assert(json['output'] == undefined ||
|
||||
json['previousStatement'] == undefined,
|
||||
@@ -1037,11 +1038,17 @@ Blockly.Block.prototype.jsonInit = function(json) {
|
||||
'strings. Found raw string in JSON for \'' + json['type'] + '\' block.');
|
||||
json['extensions'] = [json['extensions']]; // Correct and continue.
|
||||
}
|
||||
|
||||
// Add the mutator to the block
|
||||
if (json['mutator'] !== undefined) {
|
||||
Blockly.Extensions.apply(json['mutator'], this, true);
|
||||
}
|
||||
|
||||
if (Array.isArray(json['extensions'])) {
|
||||
var extensionNames = json['extensions'];
|
||||
for (var i = 0; i < extensionNames.length; ++i) {
|
||||
var extensionName = extensionNames[i];
|
||||
Blockly.Extensions.apply(extensionName, this);
|
||||
Blockly.Extensions.apply(extensionName, this, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -40,6 +40,15 @@ goog.provide('Blockly.Extensions');
|
||||
*/
|
||||
Blockly.Extensions.ALL_ = {};
|
||||
|
||||
/**
|
||||
* The set of properties on a block that may only be set by a mutator.
|
||||
* @type {!Array.<string>}
|
||||
* @private
|
||||
* @constant
|
||||
*/
|
||||
Blockly.Extensions.MUTATOR_PROPERTIES_ =
|
||||
['domToMutation', 'mutationToDom', 'compose', 'decompose'];
|
||||
|
||||
/**
|
||||
* Registers a new extension function. Extensions are functions that help
|
||||
* initialize blocks, usually adding dynamic behavior such as onchange
|
||||
@@ -76,19 +85,213 @@ Blockly.Extensions.registerMixin = function(name, mixinObj) {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Registers a new extension function that adds a mutator to the block.
|
||||
* At register time this performs some basic sanity checks on the mutator.
|
||||
* The wrapper may also add a mutator dialog to the block, if both compose and
|
||||
* decompose are defined on the mixin.
|
||||
* @param {string} name The name of this mutator extension.
|
||||
* @param {!Object} mixinObj The values to mix in.
|
||||
* @param {function()=} opt_helperFn An optional function to apply after mixing
|
||||
* in the object.
|
||||
* @param {Array.<string>=} opt_blockList A list of blocks to appear in the
|
||||
* flyout of the mutator dialog.
|
||||
* @throws {Error} if the mutation is invalid or can't be applied to the block.
|
||||
*/
|
||||
Blockly.Extensions.registerMutator = function(name, mixinObj, opt_helperFn,
|
||||
opt_blockList) {
|
||||
var errorPrefix = 'Error when registering mutator "' + name + '": ';
|
||||
|
||||
// Sanity check the mixin object before registering it.
|
||||
Blockly.Extensions.checkHasFunction_(errorPrefix, mixinObj, 'domToMutation');
|
||||
Blockly.Extensions.checkHasFunction_(errorPrefix, mixinObj, 'mutationToDom');
|
||||
|
||||
var hasMutatorDialog = Blockly.Extensions.checkMutatorDialog_(mixinObj,
|
||||
errorPrefix);
|
||||
|
||||
if (opt_helperFn && !goog.isFunction(opt_helperFn)) {
|
||||
throw new Error('Extension "' + name + '" is not a function');
|
||||
}
|
||||
|
||||
// Sanity checks passed.
|
||||
Blockly.Extensions.register(name, function() {
|
||||
if (hasMutatorDialog) {
|
||||
this.setMutator(new Blockly.Mutator(opt_blockList));
|
||||
}
|
||||
// Mixin the object.
|
||||
this.mixin(mixinObj);
|
||||
|
||||
if (opt_helperFn) {
|
||||
opt_helperFn.apply(this);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Applies an extension method to a block. This should only be called during
|
||||
* block construction.
|
||||
* @param {string} name The name of the extension.
|
||||
* @param {!Blockly.Block} block The block to apply the named extension to.
|
||||
* @param {boolean} isMutator True if this extension defines a mutator.
|
||||
* @throws {Error} if the extension is not found.
|
||||
*/
|
||||
Blockly.Extensions.apply = function(name, block) {
|
||||
Blockly.Extensions.apply = function(name, block, isMutator) {
|
||||
var extensionFn = Blockly.Extensions.ALL_[name];
|
||||
if (!goog.isFunction(extensionFn)) {
|
||||
throw new Error('Error: Extension "' + name + '" not found.');
|
||||
}
|
||||
if (isMutator) {
|
||||
// Fail early if the block already has mutation properties.
|
||||
Blockly.Extensions.checkNoMutatorProperties_(name, block);
|
||||
} else {
|
||||
// Record the old properties so we can make sure they don't change after
|
||||
// applying the extension.
|
||||
var mutatorProperties = Blockly.Extensions.getMutatorProperties_(block);
|
||||
}
|
||||
extensionFn.apply(block);
|
||||
|
||||
if (isMutator) {
|
||||
var errorPrefix = 'Error after applying mutator "' + name + '": ';
|
||||
Blockly.Extensions.checkBlockHasMutatorProperties_(name, block, errorPrefix);
|
||||
} else {
|
||||
if (!Blockly.Extensions.mutatorPropertiesMatch_(mutatorProperties, block)) {
|
||||
throw new Error('Error when applying extension "' + name +
|
||||
'": mutation properties changed when applying a non-mutator extension.');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check that the given object has a property with the given name, and that the
|
||||
* property is a function.
|
||||
* @param {string} errorPrefix The string to prepend to any error message.
|
||||
* @param {!Object} object The object to check.
|
||||
* @param {string} propertyName Which property to check.
|
||||
* @throws {Error} if the property does not exist or is not a function.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Extensions.checkHasFunction_ = function(errorPrefix, object,
|
||||
propertyName) {
|
||||
if (!object.hasOwnProperty(propertyName)) {
|
||||
throw new Error(errorPrefix +
|
||||
'missing required property "' + propertyName + '"');
|
||||
} else if (typeof object[propertyName] !== "function") {
|
||||
throw new Error(errorPrefix +
|
||||
'" required property "' + propertyName + '" must be a function');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check that the given block does not have any of the four mutator properties
|
||||
* defined on it. This function should be called before applying a mutator
|
||||
* extension to a block, to make sure we are not overwriting properties.
|
||||
* @param {string} mutationName The name of the mutation to reference in error
|
||||
* messages.
|
||||
* @param {!Blockly.Block} block The block to check.
|
||||
* @throws {Error} if any of the properties already exist on the block.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Extensions.checkNoMutatorProperties_ = function(mutationName, block) {
|
||||
for (var i = 0; i < Blockly.Extensions.MUTATOR_PROPERTIES_.length; i++) {
|
||||
var propertyName = Blockly.Extensions.MUTATOR_PROPERTIES_[i];
|
||||
if (block.hasOwnProperty(propertyName)) {
|
||||
throw new Error('Error: tried to apply mutation "' + mutationName +
|
||||
'" to a block that already has a "' + propertyName +
|
||||
'" function. Block id: ' + block.id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check that the given object has both or neither of the functions required
|
||||
* to have a mutator dialog.
|
||||
* These functions are 'compose' and 'decompose'. If a block has one, it must
|
||||
* have both.
|
||||
* @param {!Object} object The object to check.
|
||||
* @param {string} errorPrefix The string to prepend to any error message.
|
||||
* @return {boolean} True if the object has both functions. False if it has
|
||||
* neither function.
|
||||
* @throws {Error} if the object has only one of the functions.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Extensions.checkMutatorDialog_ = function(object, errorPrefix) {
|
||||
var hasCompose = object.hasOwnProperty('compose');
|
||||
var hasDecompose = object.hasOwnProperty('decompose');
|
||||
|
||||
if (hasCompose && hasDecompose) {
|
||||
if (typeof object['compose'] !== "function") {
|
||||
throw new Error(errorPrefix + 'compose must be a function.');
|
||||
} else if (typeof object['decompose'] !== "function") {
|
||||
throw new Error(errorPrefix + 'decompose must be a function.');
|
||||
}
|
||||
return true;
|
||||
} else if (!hasCompose && !hasDecompose) {
|
||||
return false;
|
||||
} else {
|
||||
throw new Error(errorPrefix +
|
||||
'Must have both or neither of "compose" and "decompose"');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check that a block has required mutator properties. This should be called
|
||||
* after applying a mutation extension.
|
||||
* @param {string} errorPrefix The string to prepend to any error message.
|
||||
* @param {!Blockly.Block} block The block to inspect.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Extensions.checkBlockHasMutatorProperties_ = function(errorPrefix,
|
||||
block) {
|
||||
if (!block.hasOwnProperty('domToMutation')) {
|
||||
throw new Error(errorPrefix + 'Applying a mutator didn\'t add "domToMutation"');
|
||||
}
|
||||
if (!block.hasOwnProperty('mutationToDom')) {
|
||||
throw new Error(errorPrefix + 'Applying a mutator didn\'t add "mutationToDom"');
|
||||
}
|
||||
|
||||
// A block with a mutator isn't required to have a mutation dialog, but
|
||||
// it should still have both or neither of compose and decompose.
|
||||
Blockly.Extensions.checkMutatorDialog_(block, errorPrefix);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a list of values of mutator properties on the given block.
|
||||
* @param {!Blockly.Block} block The block to inspect.
|
||||
* @return {!Array.<Object>} a list with all of the properties, which should be
|
||||
* functions or undefined, but are not guaranteed to be.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Extensions.getMutatorProperties_ = function(block) {
|
||||
var result = [];
|
||||
for (var i = 0; i < Blockly.Extensions.MUTATOR_PROPERTIES_.length; i++) {
|
||||
result.push(block[Blockly.Extensions.MUTATOR_PROPERTIES_[i]]);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check that the current mutator properties match a list of old mutator
|
||||
* properties. This should be called after applying a non-mutator extension,
|
||||
* to verify that the extension didn't change properties it shouldn't.
|
||||
* @param {!Array.<Object>} oldProperties The old values to compare to.
|
||||
* @param {!Blockly.Block} block The block to inspect for new values.
|
||||
* @return {boolean} True if the property lists match.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Extensions.mutatorPropertiesMatch_ = function(oldProperties, block) {
|
||||
var match = true;
|
||||
var newProperties = Blockly.Extensions.getMutatorProperties_(block);
|
||||
if (newProperties.length != oldProperties.length) {
|
||||
match = false;
|
||||
} else {
|
||||
for (var i = 0; i < newProperties.length; i++) {
|
||||
if (oldProperties[i] != newProperties[i]) {
|
||||
match = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return match;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -239,3 +442,5 @@ Blockly.Extensions.extensionParentTooltip_ = function() {
|
||||
};
|
||||
Blockly.Extensions.register('parent_tooltip_when_inline',
|
||||
Blockly.Extensions.extensionParentTooltip_);
|
||||
|
||||
|
||||
|
||||
@@ -304,3 +304,354 @@ function test_bad_mixin_overwrites_prototype() {
|
||||
delete Blockly.Blocks['test_block_bad_colour'];
|
||||
}
|
||||
}
|
||||
|
||||
function test_mutator_mixin() {
|
||||
var workspace = new Blockly.Workspace();
|
||||
var block;
|
||||
|
||||
try {
|
||||
Blockly.defineBlocksWithJsonArray([{
|
||||
"type": "mutator_test_block",
|
||||
"message0": "mutator_test_block",
|
||||
"mutator": "mutator_test"
|
||||
}]);
|
||||
|
||||
// Events code calls mutationToDom and expects it to give back a meaningful
|
||||
// value.
|
||||
Blockly.Events.disable();
|
||||
Blockly.Extensions.registerMutator('mutator_test',
|
||||
{
|
||||
domToMutation: function() {
|
||||
return 'domToMutationFn';
|
||||
},
|
||||
mutationToDom: function() {
|
||||
return 'mutationToDomFn';
|
||||
},
|
||||
compose: function() {
|
||||
return 'composeFn';
|
||||
},
|
||||
decompose: function() {
|
||||
return 'decomposeFn';
|
||||
}
|
||||
});
|
||||
|
||||
block = new Blockly.Block(workspace, 'mutator_test_block');
|
||||
|
||||
// Make sure all of the functions were installed correctly.
|
||||
assertEquals(block.domToMutation(), 'domToMutationFn');
|
||||
assertEquals(block.mutationToDom(), 'mutationToDomFn');
|
||||
assertEquals(block.compose(), 'composeFn');
|
||||
assertEquals(block.decompose(), 'decomposeFn');
|
||||
} finally {
|
||||
if (block) {
|
||||
block.dispose();
|
||||
}
|
||||
workspace.dispose();
|
||||
Blockly.Events.enable();
|
||||
delete Blockly.Extensions.ALL_['mutator_test'];
|
||||
}
|
||||
}
|
||||
|
||||
function test_mutator_mixin_no_dialog() {
|
||||
var workspace = new Blockly.Workspace();
|
||||
var block;
|
||||
|
||||
try {
|
||||
Blockly.defineBlocksWithJsonArray([{
|
||||
"type": "mutator_test_block",
|
||||
"message0": "mutator_test_block",
|
||||
"mutator": "mutator_test"
|
||||
}]);
|
||||
|
||||
// Events code calls mutationToDom and expects it to give back a meaningful
|
||||
// value.
|
||||
Blockly.Events.disable();
|
||||
assertUndefined(Blockly.Extensions.ALL_['mutator_test']);
|
||||
Blockly.Extensions.registerMutator('mutator_test',
|
||||
{
|
||||
domToMutation: function() {
|
||||
return 'domToMutationFn';
|
||||
},
|
||||
mutationToDom: function() {
|
||||
return 'mutationToDomFn';
|
||||
}
|
||||
});
|
||||
|
||||
block = new Blockly.Block(workspace, 'mutator_test_block');
|
||||
|
||||
// Make sure all of the functions were installed correctly.
|
||||
assertEquals(block.domToMutation(), 'domToMutationFn');
|
||||
assertEquals(block.mutationToDom(), 'mutationToDomFn');
|
||||
assertFalse(block.hasOwnProperty('compose'));
|
||||
assertFalse(block.hasOwnProperty('decompose'));
|
||||
} finally {
|
||||
if (block) {
|
||||
block.dispose();
|
||||
}
|
||||
workspace.dispose();
|
||||
Blockly.Events.enable();
|
||||
delete Blockly.Extensions.ALL_['mutator_test'];
|
||||
}
|
||||
}
|
||||
|
||||
// Explicitly check all four things that could be missing.
|
||||
function test_mutator_mixin_no_decompose_fails() {
|
||||
var exceptionWasThrown = false;
|
||||
try {
|
||||
Blockly.Extensions.registerMutator('mutator_test',
|
||||
{
|
||||
domToMutation: function() {
|
||||
return 'domToMutationFn';
|
||||
},
|
||||
mutationToDom: function() {
|
||||
return 'mutationToDomFn';
|
||||
},
|
||||
compose: function() {
|
||||
return 'composeFn';
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
// Expected.
|
||||
exceptionWasThrown = true;
|
||||
} finally {
|
||||
delete Blockly.Extensions.ALL_['mutator_test'];
|
||||
}
|
||||
assertTrue(exceptionWasThrown);
|
||||
}
|
||||
|
||||
function test_mutator_mixin_no_compose_fails() {
|
||||
var exceptionWasThrown = false;
|
||||
try {
|
||||
Blockly.Extensions.registerMutator('mutator_test',
|
||||
{
|
||||
domToMutation: function() {
|
||||
return 'domToMutationFn';
|
||||
},
|
||||
mutationToDom: function() {
|
||||
return 'mutationToDomFn';
|
||||
},
|
||||
decompose: function() {
|
||||
return 'decomposeFn';
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
// Expected.
|
||||
exceptionWasThrown = true;
|
||||
} finally {
|
||||
delete Blockly.Extensions.ALL_['mutator_test'];
|
||||
}
|
||||
assertTrue(exceptionWasThrown);
|
||||
}
|
||||
|
||||
function test_mutator_mixin_no_domToMutation_fails() {
|
||||
var exceptionWasThrown = false;
|
||||
try {
|
||||
Blockly.Extensions.registerMutator('mutator_test',
|
||||
{
|
||||
mutationToDom: function() {
|
||||
return 'mutationToDomFn';
|
||||
},
|
||||
compose: function() {
|
||||
return 'composeFn';
|
||||
},
|
||||
decompose: function() {
|
||||
return 'decomposeFn';
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
// Expected.
|
||||
exceptionWasThrown = true;
|
||||
} finally {
|
||||
delete Blockly.Extensions.ALL_['mutator_test'];
|
||||
}
|
||||
assertTrue(exceptionWasThrown);
|
||||
}
|
||||
|
||||
function test_mutator_mixin_no_mutationToDom_fails() {
|
||||
var exceptionWasThrown = false;
|
||||
try {
|
||||
Blockly.Extensions.registerMutator('mutator_test',
|
||||
{
|
||||
domToMutation: function() {
|
||||
return 'domToMutationFn';
|
||||
},
|
||||
compose: function() {
|
||||
return 'composeFn';
|
||||
},
|
||||
decompose: function() {
|
||||
return 'decomposeFn';
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
// Expected.
|
||||
exceptionWasThrown = true;
|
||||
} finally {
|
||||
delete Blockly.Extensions.ALL_['mutator_test'];
|
||||
}
|
||||
assertTrue(exceptionWasThrown);
|
||||
}
|
||||
|
||||
function test_use_mutator_as_extension_fails() {
|
||||
var workspace = new Blockly.Workspace();
|
||||
var block;
|
||||
var exceptionWasThrown = false;
|
||||
|
||||
try {
|
||||
Blockly.defineBlocksWithJsonArray([{
|
||||
"type": "mutator_test_block",
|
||||
"message0": "mutator_test_block",
|
||||
"extensions": ["mutator_test"]
|
||||
}]);
|
||||
|
||||
Blockly.Events.disable();
|
||||
assertUndefined(Blockly.Extensions.ALL_['mutator_test']);
|
||||
Blockly.Extensions.registerMutator('mutator_test',
|
||||
{
|
||||
domToMutation: function() {
|
||||
return 'domToMutationFn';
|
||||
},
|
||||
mutationToDom: function() {
|
||||
return 'mutationToDomFn';
|
||||
}
|
||||
});
|
||||
|
||||
// Events code calls mutationToDom and expects it to give back a meaningful
|
||||
// value.
|
||||
block = new Blockly.Block(workspace, 'mutator_test_block');
|
||||
} catch (e) {
|
||||
// Expected
|
||||
exceptionWasThrown = true;
|
||||
// Should have failed on apply, not on register.
|
||||
assertNotNull(Blockly.Extensions.ALL_['mutator_test']);
|
||||
} finally {
|
||||
if (block) {
|
||||
block.dispose();
|
||||
}
|
||||
workspace.dispose();
|
||||
Blockly.Events.enable();
|
||||
delete Blockly.Extensions.ALL_['mutator_test'];
|
||||
}
|
||||
assertTrue(exceptionWasThrown);
|
||||
}
|
||||
|
||||
function test_use_mutator_mixin_as_extension_fails() {
|
||||
var workspace = new Blockly.Workspace();
|
||||
var block;
|
||||
var exceptionWasThrown = false;
|
||||
|
||||
try {
|
||||
Blockly.defineBlocksWithJsonArray([{
|
||||
"type": "mutator_test_block",
|
||||
"message0": "mutator_test_block",
|
||||
"extensions": ["mutator_test"]
|
||||
}]);
|
||||
|
||||
// Events code calls mutationToDom and expects it to give back a meaningful
|
||||
// value.
|
||||
Blockly.Events.disable();
|
||||
assertUndefined(Blockly.Extensions.ALL_['mutator_test']);
|
||||
Blockly.Extensions.registerMixin('mutator_test',
|
||||
{
|
||||
domToMutation: function() {
|
||||
return 'domToMutationFn';
|
||||
},
|
||||
mutationToDom: function() {
|
||||
return 'mutationToDomFn';
|
||||
}
|
||||
});
|
||||
|
||||
block = new Blockly.Block(workspace, 'mutator_test_block');
|
||||
} catch (e) {
|
||||
// Expected
|
||||
exceptionWasThrown = true;
|
||||
// Should have failed on apply, not on register.
|
||||
assertNotNull(Blockly.Extensions.ALL_['mutator_test']);
|
||||
} finally {
|
||||
if (block) {
|
||||
block.dispose();
|
||||
}
|
||||
workspace.dispose();
|
||||
Blockly.Events.enable();
|
||||
delete Blockly.Extensions.ALL_['mutator_test'];
|
||||
}
|
||||
assertTrue(exceptionWasThrown);
|
||||
}
|
||||
|
||||
function test_use_extension_as_mutator_fails() {
|
||||
var workspace = new Blockly.Workspace();
|
||||
var block;
|
||||
var exceptionWasThrown = false;
|
||||
|
||||
try {
|
||||
Blockly.defineBlocksWithJsonArray([{
|
||||
"type": "mutator_test_block",
|
||||
"message0": "mutator_test_block",
|
||||
"mutator": ["extensions_test"]
|
||||
}]);
|
||||
|
||||
// Events code calls mutationToDom and expects it to give back a meaningful
|
||||
// value.
|
||||
Blockly.Events.disable();
|
||||
assertUndefined(Blockly.Extensions.ALL_['extensions_test']);
|
||||
Blockly.Extensions.register('extensions_test', function() {
|
||||
return 'extensions_test_fn';
|
||||
});
|
||||
|
||||
block = new Blockly.Block(workspace, 'mutator_test_block');
|
||||
} catch (e) {
|
||||
// Expected
|
||||
exceptionWasThrown = true;
|
||||
// Should have failed on apply, not on register.
|
||||
assertNotNull(Blockly.Extensions.ALL_['extensions_test']);
|
||||
} finally {
|
||||
if (block) {
|
||||
block.dispose();
|
||||
}
|
||||
workspace.dispose();
|
||||
Blockly.Events.enable();
|
||||
delete Blockly.Extensions.ALL_['extensions_test'];
|
||||
}
|
||||
assertTrue(exceptionWasThrown);
|
||||
}
|
||||
|
||||
function test_mutator_mixin_plus_function() {
|
||||
var workspace = new Blockly.Workspace();
|
||||
var block;
|
||||
var fnWasCalled = false;
|
||||
|
||||
try {
|
||||
Blockly.defineBlocksWithJsonArray([{
|
||||
"type": "mutator_test_block",
|
||||
"message0": "mutator_test_block",
|
||||
"mutator": ["extensions_test"]
|
||||
}]);
|
||||
|
||||
Blockly.Events.disable();
|
||||
assertUndefined(Blockly.Extensions.ALL_['extensions_test']);
|
||||
Blockly.Extensions.registerMutator('extensions_test',
|
||||
{
|
||||
domToMutation: function() {
|
||||
return 'domToMutationFn';
|
||||
},
|
||||
mutationToDom: function() {
|
||||
return 'mutationToDomFn';
|
||||
}
|
||||
},
|
||||
function() {
|
||||
fnWasCalled = true;
|
||||
}
|
||||
);
|
||||
|
||||
// Events code calls mutationToDom and expects it to give back a meaningful
|
||||
// value.
|
||||
block = new Blockly.Block(workspace, 'mutator_test_block');
|
||||
} finally {
|
||||
if (block) {
|
||||
block.dispose();
|
||||
}
|
||||
workspace.dispose();
|
||||
Blockly.Events.enable();
|
||||
delete Blockly.Extensions.ALL_['extensions_test'];
|
||||
}
|
||||
assertTrue(fnWasCalled);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user