mirror of
https://github.com/google/blockly.git
synced 2026-01-05 08:00:09 +01:00
fix(events): Simplify filter function, add new enqueueEvent function (#8539)
* docs(events): JSDoc improvments * fix(filter): Introduce enqueueEvent; don't reorder in filter Remove the broken BlockChange event reordering code from filter. Instead, do necessary event reordering (correctly, this time) in a new enqueueEvent function used by fireInternal. * chore(events): Deprecate forward parameter of filter Since we don't filter in undo any more, and filtering in reverse order causes problems, prepare to remove this opportunity for error. * fix(events): Only merge adjacent events Simplify filter by having it consider only adjacent events in the queue for merging. Previously any events in the queue could potentially be merged if they were of suitable (typically identical) .type, even if other events had occurred between them (with the sole exception of BlockMove events, which would only be merged with adjacent events). This could potentially result in replay failures during undo/redo/mirroring, though it is unknown whether any such problems occurred in practice. * refactor(events): Tweaks - Use for…of loop where appropriate. - Make filter reason-merging code more concise. - Use arrow functions when calling Array.prototype.filter. * chore(events): Fix typos for PR #8539.
This commit is contained in:
committed by
GitHub
parent
07da975b63
commit
a7afda8343
@@ -42,6 +42,26 @@ suite('Events', function () {
|
||||
'type': 'simple_test_block',
|
||||
'message0': 'simple test block',
|
||||
},
|
||||
{
|
||||
'type': 'inputs_test_block',
|
||||
'message0': 'first %1 second %2',
|
||||
'args0': [
|
||||
{
|
||||
'type': 'input_statement',
|
||||
'name': 'STATEMENT1',
|
||||
},
|
||||
{
|
||||
'type': 'input_statement',
|
||||
'name': 'STATEMENT2',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'type': 'statement_test_block',
|
||||
'message0': '',
|
||||
'previousStatement': null,
|
||||
'nextStatement': null,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -1102,6 +1122,165 @@ suite('Events', function () {
|
||||
});
|
||||
});
|
||||
|
||||
suite('enqueueEvent', function () {
|
||||
const {FIRE_QUEUE, enqueueEvent} = eventUtils.TEST_ONLY;
|
||||
|
||||
function newDisconnectEvent(parent, child, inputName, workspaceId) {
|
||||
const event = new Blockly.Events.BlockMove(child);
|
||||
event.workspaceId = workspaceId;
|
||||
event.oldParentId = parent.id;
|
||||
event.oldInputName = inputName;
|
||||
event.oldCoordinate = undefined;
|
||||
event.newParentId = undefined;
|
||||
event.newInputName = undefined;
|
||||
event.newCoordinate = new Blockly.utils.Coordinate(0, 0);
|
||||
return event;
|
||||
}
|
||||
|
||||
function newConnectEvent(parent, child, inputName, workspaceId) {
|
||||
const event = new Blockly.Events.BlockMove(child);
|
||||
event.workspaceId = workspaceId;
|
||||
event.oldParentId = undefined;
|
||||
event.oldInputName = undefined;
|
||||
event.oldCoordinate = new Blockly.utils.Coordinate(0, 0);
|
||||
event.newParentId = parent.id;
|
||||
event.newInputName = inputName;
|
||||
event.newCoordinate = undefined;
|
||||
return event;
|
||||
}
|
||||
|
||||
function newMutationEvent(block, workspaceId) {
|
||||
const event = new Blockly.Events.BlockChange(block);
|
||||
event.workspaceId = workspaceId;
|
||||
event.element = 'mutation';
|
||||
return event;
|
||||
}
|
||||
|
||||
test('Events are enqueued', function () {
|
||||
// Disable events during block creation to avoid firing BlockCreate
|
||||
// events.
|
||||
eventUtils.disable();
|
||||
const block = this.workspace.newBlock('simple_test_block', '1');
|
||||
eventUtils.enable();
|
||||
|
||||
try {
|
||||
assert.equal(FIRE_QUEUE.length, 0);
|
||||
const events = [
|
||||
new Blockly.Events.BlockCreate(block),
|
||||
new Blockly.Events.BlockMove(block),
|
||||
new Blockly.Events.Click(block),
|
||||
];
|
||||
events.map((e) => enqueueEvent(e));
|
||||
assert.equal(FIRE_QUEUE.length, events.length, 'FIRE_QUEUE.length');
|
||||
for (let i = 0; i < events.length; i++) {
|
||||
assert.equal(FIRE_QUEUE[i], events[i], `FIRE_QUEUE[${i}]`);
|
||||
}
|
||||
} finally {
|
||||
FIRE_QUEUE.length = 0;
|
||||
}
|
||||
});
|
||||
|
||||
test('BlockChange event reordered', function () {
|
||||
eventUtils.disable();
|
||||
const parent = this.workspace.newBlock('inputs_test_block', 'parent');
|
||||
const child1 = this.workspace.newBlock('statement_test_block', 'child1');
|
||||
const child2 = this.workspace.newBlock('statement_test_block', 'child2');
|
||||
eventUtils.enable();
|
||||
|
||||
try {
|
||||
assert.equal(FIRE_QUEUE.length, 0);
|
||||
const events = [
|
||||
newDisconnectEvent(parent, child1, 'STATEMENT1'),
|
||||
newDisconnectEvent(parent, child2, 'STATEMENT2'),
|
||||
newConnectEvent(parent, child1, 'STATEMENT1'),
|
||||
newConnectEvent(parent, child2, 'STATEMENT2'),
|
||||
newMutationEvent(parent),
|
||||
];
|
||||
events.map((e) => enqueueEvent(e));
|
||||
assert.equal(FIRE_QUEUE.length, events.length, 'FIRE_QUEUE.length');
|
||||
assert.equal(FIRE_QUEUE[0], events[0], 'FIRE_QUEUE[0]');
|
||||
assert.equal(FIRE_QUEUE[1], events[1], 'FIRE_QUEUE[1]');
|
||||
assert.equal(FIRE_QUEUE[2], events[4], 'FIRE_QUEUE[2]');
|
||||
assert.equal(FIRE_QUEUE[3], events[2], 'FIRE_QUEUE[3]');
|
||||
assert.equal(FIRE_QUEUE[4], events[3], 'FIRE_QUEUE[4]');
|
||||
} finally {
|
||||
FIRE_QUEUE.length = 0;
|
||||
}
|
||||
});
|
||||
|
||||
test('BlockChange event for other workspace not reordered', function () {
|
||||
eventUtils.disable();
|
||||
const parent = this.workspace.newBlock('inputs_test_block', 'parent');
|
||||
const child = this.workspace.newBlock('statement_test_block', 'child');
|
||||
eventUtils.enable();
|
||||
|
||||
try {
|
||||
assert.equal(FIRE_QUEUE.length, 0);
|
||||
const events = [
|
||||
newDisconnectEvent(parent, child, 'STATEMENT1', 'ws1'),
|
||||
newConnectEvent(parent, child, 'STATEMENT1', 'ws1'),
|
||||
newMutationEvent(parent, 'ws2'),
|
||||
];
|
||||
events.map((e) => enqueueEvent(e));
|
||||
assert.equal(FIRE_QUEUE.length, events.length, 'FIRE_QUEUE.length');
|
||||
for (let i = 0; i < events.length; i++) {
|
||||
assert.equal(FIRE_QUEUE[i], events[i], `FIRE_QUEUE[${i}]`);
|
||||
}
|
||||
} finally {
|
||||
FIRE_QUEUE.length = 0;
|
||||
}
|
||||
});
|
||||
|
||||
test('BlockChange event for other group not reordered', function () {
|
||||
eventUtils.disable();
|
||||
const parent = this.workspace.newBlock('inputs_test_block', 'parent');
|
||||
const child = this.workspace.newBlock('statement_test_block', 'child');
|
||||
eventUtils.enable();
|
||||
|
||||
try {
|
||||
assert.equal(FIRE_QUEUE.length, 0);
|
||||
const events = [];
|
||||
eventUtils.setGroup('group1');
|
||||
events.push(newDisconnectEvent(parent, child, 'STATEMENT1'));
|
||||
events.push(newConnectEvent(parent, child, 'STATEMENT1'));
|
||||
eventUtils.setGroup('group2');
|
||||
events.push(newMutationEvent(parent, 'ws2'));
|
||||
events.map((e) => enqueueEvent(e));
|
||||
assert.equal(FIRE_QUEUE.length, events.length, 'FIRE_QUEUE.length');
|
||||
for (let i = 0; i < events.length; i++) {
|
||||
assert.equal(FIRE_QUEUE[i], events[i], `FIRE_QUEUE[${i}]`);
|
||||
}
|
||||
} finally {
|
||||
FIRE_QUEUE.length = 0;
|
||||
eventUtils.setGroup(false);
|
||||
}
|
||||
});
|
||||
|
||||
test('BlockChange event for other parent not reordered', function () {
|
||||
eventUtils.disable();
|
||||
const parent1 = this.workspace.newBlock('inputs_test_block', 'parent1');
|
||||
const parent2 = this.workspace.newBlock('inputs_test_block', 'parent2');
|
||||
const child = this.workspace.newBlock('statement_test_block', 'child');
|
||||
eventUtils.enable();
|
||||
|
||||
try {
|
||||
assert.equal(FIRE_QUEUE.length, 0);
|
||||
const events = [
|
||||
newDisconnectEvent(parent1, child, 'STATEMENT1', 'ws1'),
|
||||
newConnectEvent(parent1, child, 'STATEMENT1', 'ws1'),
|
||||
newMutationEvent(parent2, 'ws2'),
|
||||
];
|
||||
events.map((e) => enqueueEvent(e));
|
||||
assert.equal(FIRE_QUEUE.length, events.length, 'FIRE_QUEUE.length');
|
||||
for (let i = 0; i < events.length; i++) {
|
||||
assert.equal(FIRE_QUEUE[i], events[i], `FIRE_QUEUE[${i}]`);
|
||||
}
|
||||
} finally {
|
||||
FIRE_QUEUE.length = 0;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
suite('Filters', function () {
|
||||
function addMoveEvent(events, block, newX, newY) {
|
||||
events.push(new Blockly.Events.BlockMove(block));
|
||||
|
||||
Reference in New Issue
Block a user