fix: insertion markers and change events to work with JSO hooks (#5378)

* fix: add tests for fixing change events

* fix: change events and insertion markers

* fix: build:

* fix: remove duplicate code

* fix: requires
This commit is contained in:
Beka Westberg
2021-08-19 20:17:54 +00:00
committed by alschmiedt
parent 1d4cbd1ab6
commit 486123e4ff
10 changed files with 287 additions and 22 deletions

View File

@@ -130,7 +130,7 @@ goog.addDependency('../../core/menu.js', ['Blockly.Menu'], ['Blockly.browserEven
goog.addDependency('../../core/menuitem.js', ['Blockly.MenuItem'], ['Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.idGenerator'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/metrics_manager.js', ['Blockly.MetricsManager'], ['Blockly.registry', 'Blockly.utils.Size', 'Blockly.utils.toolbox'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/msg.js', ['Blockly.Msg'], ['Blockly.utils.global'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/mutator.js', ['Blockly.Mutator'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BubbleOpen', 'Blockly.Icon', 'Blockly.Options', 'Blockly.WorkspaceSvg', 'Blockly.Xml', 'Blockly.internalConstants', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.toolbox', 'Blockly.utils.xml'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/mutator.js', ['Blockly.Mutator'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BubbleOpen', 'Blockly.Icon', 'Blockly.Options', 'Blockly.WorkspaceSvg', 'Blockly.internalConstants', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.toolbox', 'Blockly.utils.xml'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/names.js', ['Blockly.Names'], ['Blockly.Msg', 'Blockly.Variables', 'Blockly.internalConstants'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/options.js', ['Blockly.Options'], ['Blockly.Theme', 'Blockly.Themes.Classic', 'Blockly.registry', 'Blockly.utils.deprecation', 'Blockly.utils.idGenerator', 'Blockly.utils.toolbox'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/positionable_helpers.js', ['Blockly.uiPosition'], ['Blockly.Scrollbar', 'Blockly.utils.Rect', 'Blockly.utils.toolbox'], {'lang': 'es6', 'module': 'goog'});

View File

@@ -130,7 +130,7 @@ goog.addDependency('../../core/menu.js', ['Blockly.Menu'], ['Blockly.browserEven
goog.addDependency('../../core/menuitem.js', ['Blockly.MenuItem'], ['Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.idGenerator'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/metrics_manager.js', ['Blockly.MetricsManager'], ['Blockly.registry', 'Blockly.utils.Size', 'Blockly.utils.toolbox'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/msg.js', ['Blockly.Msg'], ['Blockly.utils.global'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/mutator.js', ['Blockly.Mutator'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BubbleOpen', 'Blockly.Icon', 'Blockly.Options', 'Blockly.WorkspaceSvg', 'Blockly.Xml', 'Blockly.internalConstants', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.toolbox', 'Blockly.utils.xml'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/mutator.js', ['Blockly.Mutator'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BubbleOpen', 'Blockly.Icon', 'Blockly.Options', 'Blockly.WorkspaceSvg', 'Blockly.internalConstants', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.toolbox', 'Blockly.utils.xml'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/names.js', ['Blockly.Names'], ['Blockly.Msg', 'Blockly.Variables', 'Blockly.internalConstants'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/options.js', ['Blockly.Options'], ['Blockly.Theme', 'Blockly.Themes.Classic', 'Blockly.registry', 'Blockly.utils.deprecation', 'Blockly.utils.idGenerator', 'Blockly.utils.toolbox'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/positionable_helpers.js', ['Blockly.uiPosition'], ['Blockly.Scrollbar', 'Blockly.utils.Rect', 'Blockly.utils.toolbox'], {'lang': 'es6', 'module': 'goog'});
@@ -303,6 +303,7 @@ goog.addDependency('../../generators/python/variables.js', ['Blockly.Python.vari
goog.addDependency('../../generators/python/variables_dynamic.js', ['Blockly.Python.variablesDynamic'], ['Blockly.Python', 'Blockly.Python.variables']);
goog.addDependency('../../tests/mocha/.mocharc.js', [], []);
goog.addDependency('../../tests/mocha/astnode_test.js', ['Blockly.test.astNode'], ['Blockly.test.helpers'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../tests/mocha/block_change_event_test.js', ['Blockly.test.blockChangeEvent'], ['Blockly.test.helpers'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../tests/mocha/block_json_test.js', ['Blockly.test.blockJson'], [], {'lang': 'es5', 'module': 'goog'});
goog.addDependency('../../tests/mocha/block_test.js', ['Blockly.test.blocks'], ['Blockly.test.helpers'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../tests/mocha/comment_test.js', ['Blockly.test.comments'], ['Blockly.test.helpers'], {'lang': 'es6', 'module': 'goog'});
@@ -338,6 +339,7 @@ goog.addDependency('../../tests/mocha/json_test.js', ['Blockly.test.json'], ['Bl
goog.addDependency('../../tests/mocha/keydown_test.js', ['Blockly.test.keydown'], ['Blockly.test.helpers'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../tests/mocha/logic_ternary_test.js', ['Blockly.test.logicTernary'], ['Blockly.test.helpers'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../tests/mocha/metrics_test.js', ['Blockly.test.metrics'], ['Blockly.test.helpers'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../tests/mocha/mutator_test.js', ['Blockly.test.mutator'], ['Blockly.test.helpers'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../tests/mocha/names_test.js', ['Blockly.test.names'], ['Blockly.test.helpers'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../tests/mocha/procedures_test.js', ['Blockly.test.procedures'], ['Blockly.Blocks.procedures', 'Blockly.Msg', 'Blockly.test.helpers', 'Blockly.test.procedureHelpers'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../tests/mocha/procedures_test_helpers.js', ['Blockly.test.procedureHelpers'], [], {'lang': 'es6', 'module': 'goog'});

View File

@@ -0,0 +1,74 @@
/**
* @license
* Copyright 2021 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
goog.module('Blockly.test.blockChangeEvent');
const {defineMutatorBlocks, sharedTestSetup, sharedTestTeardown} = goog.require('Blockly.test.helpers');
suite('Block Change Event', function() {
setup(function() {
sharedTestSetup.call(this);
this.workspace = new Blockly.Workspace();
});
teardown(function() {
sharedTestTeardown.call(this);
});
suite('Undo and Redo', function() {
suite('Mutation', function() {
setup(function() {
defineMutatorBlocks();
});
teardown(function() {
Blockly.Extensions.unregister('xml_mutator');
Blockly.Extensions.unregister('jso_mutator');
});
suite('XML', function() {
test('Undo', function() {
const block = this.workspace.newBlock('xml_block', 'block_id');
block.domToMutation(
Blockly.Xml.textToDom('<mutation hasInput="true"/>'));
const blockChange = new Blockly.Events.BlockChange(
block, 'mutation', null, '', '<mutation hasInput="true"/>');
blockChange.run(false);
chai.assert.isFalse(block.hasInput);
});
test('Redo', function() {
const block = this.workspace.newBlock('xml_block', 'block_id');
const blockChange = new Blockly.Events.BlockChange(
block, 'mutation', null, '', '<mutation hasInput="true"/>');
blockChange.run(true);
chai.assert.isTrue(block.hasInput);
});
});
suite('JSO', function() {
test('Undo', function() {
const block = this.workspace.newBlock('jso_block', 'block_id');
block.loadExtraState({hasInput: true});
const blockChange = new Blockly.Events.BlockChange(
block, 'mutation', null, '', '{"hasInput":true}');
blockChange.run(false);
chai.assert.isFalse(block.hasInput);
});
test('Redo', function() {
const block = this.workspace.newBlock('jso_block', 'block_id');
const blockChange = new Blockly.Events.BlockChange(
block, 'mutation', null, '', '{"hasInput":true}');
blockChange.run(true);
chai.assert.isTrue(block.hasInput);
});
});
});
});
});

View File

@@ -53,6 +53,7 @@
<script>
goog.require('Blockly.test.astNode');
goog.require('Blockly.test.blockChangeEvent');
goog.require('Blockly.test.blockJson');
goog.require('Blockly.test.blocks');
goog.require('Blockly.test.comments');
@@ -88,6 +89,7 @@
goog.require('Blockly.test.keydown');
goog.require('Blockly.test.logicTernary');
goog.require('Blockly.test.metrics');
goog.require('Blockly.test.mutator');
goog.require('Blockly.test.names');
goog.require('Blockly.test.procedures');
goog.require('Blockly.test.registry');

View File

@@ -0,0 +1,71 @@
/**
* @license
* Copyright 2021 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
goog.module('Blockly.test.mutator');
const {createRenderedBlock, defineMutatorBlocks, sharedTestSetup, sharedTestTeardown} = goog.require('Blockly.test.helpers');
suite('Mutator', function() {
setup(function() {
sharedTestSetup.call(this);
});
suite('Firing change event', function() {
setup(function() {
this.workspace = Blockly.inject('blocklyDiv', {});
defineMutatorBlocks();
});
teardown(function() {
Blockly.Extensions.unregister('xml_mutator');
Blockly.Extensions.unregister('jso_mutator');
sharedTestTeardown.call(this);
});
test('No change', function() {
var block = createRenderedBlock(this.workspace, 'xml_block');
block.mutator.setVisible(true);
var mutatorWorkspace = block.mutator.getWorkspace();
// Trigger mutator change listener.
createRenderedBlock(mutatorWorkspace, 'checkbox_block');
chai.assert.isTrue(
this.eventsFireStub.getCalls().every(
({args}) =>
args[0].type !== Blockly.Events.BLOCK_CHANGE ||
args[0].element !== 'mutation'));
});
test('XML', function() {
var block = createRenderedBlock(this.workspace, 'xml_block');
block.mutator.setVisible(true);
var mutatorWorkspace = block.mutator.getWorkspace();
mutatorWorkspace.getBlockById('check_block')
.setFieldValue('TRUE', 'CHECK');
chai.assert.isTrue(
this.eventsFireStub.getCalls().some(
({args}) =>
args[0].type === Blockly.Events.BLOCK_CHANGE &&
args[0].element === 'mutation' &&
/<mutation.*><\/mutation>/.test(args[0].newValue)));
});
test('JSO', function() {
var block = createRenderedBlock(this.workspace, 'jso_block');
block.mutator.setVisible(true);
var mutatorWorkspace = block.mutator.getWorkspace();
mutatorWorkspace.getBlockById('check_block')
.setFieldValue('TRUE', 'CHECK');
chai.assert.isTrue(
this.eventsFireStub.getCalls().some(
({args}) =>
args[0].type === Blockly.Events.BLOCK_CHANGE &&
args[0].element === 'mutation' &&
args[0].newValue === '{"hasInput":true}'));
});
});
});

View File

@@ -540,6 +540,100 @@ function defineBasicBlockWithField() {
}
exports.defineBasicBlockWithField = defineBasicBlockWithField;
function defineMutatorBlocks() {
Blockly.defineBlocksWithJsonArray([
{
'type': 'xml_block',
'mutator': 'xml_mutator'
},
{
'type': 'jso_block',
'mutator': 'jso_mutator'
},
{
'type': 'checkbox_block',
'message0': '%1',
'args0': [
{
'type': 'field_checkbox',
'name': 'CHECK'
}
]
}
]);
const xmlMutator = {
hasInput: false,
mutationToDom: function() {
var mutation = Blockly.utils.xml.createElement('mutation');
mutation.setAttribute('hasInput', this.hasInput);
return mutation;
},
domToMutation: function(mutation) {
this.hasInput = mutation.getAttribute('hasInput') == 'true';
this.updateShape();
},
decompose: function(workspace) {
var topBlock = workspace.newBlock('checkbox_block', 'check_block');
topBlock.initSvg();
topBlock.render();
return topBlock;
},
compose: function(topBlock) {
this.hasInput = topBlock.getFieldValue('CHECK') == 'TRUE';
this.updateShape();
},
updateShape: function() {
if (this.hasInput && !this.getInput('INPUT')) {
this.appendValueInput('INPUT');
} else if (!this.hasInput && this.getInput('INPUT')) {
this.removeInput('INPUT');
}
}
};
Blockly.Extensions.registerMutator('xml_mutator', xmlMutator);
const jsoMutator = {
hasInput: false,
saveExtraState: function() {
return {hasInput: this.hasInput};
},
loadExtraState: function(state) {
this.hasInput = state.hasInput || false;
this.updateShape();
},
decompose: function(workspace) {
var topBlock = workspace.newBlock('checkbox_block', 'check_block');
topBlock.initSvg();
topBlock.render();
return topBlock;
},
compose: function(topBlock) {
this.hasInput = topBlock.getFieldValue('CHECK') == 'TRUE';
this.updateShape();
},
updateShape: function() {
if (this.hasInput && !this.getInput('INPUT')) {
this.appendValueInput('INPUT');
} else if (!this.hasInput && this.getInput('INPUT')) {
this.removeInput('INPUT');
}
}
};
Blockly.Extensions.registerMutator('jso_mutator', jsoMutator);
}
exports.defineMutatorBlocks = defineMutatorBlocks;
function createTestBlock() {
return {
id: 'test',