diff --git a/core/block_dragger.js b/core/block_dragger.js index 21e3994c9..b3e459c57 100644 --- a/core/block_dragger.js +++ b/core/block_dragger.js @@ -225,8 +225,12 @@ Blockly.BlockDragger.prototype.endBlockDrag = function(e, currentDragDeltaXY) { this.draggingBlock_.moveConnections_(delta.x, delta.y); this.draggingBlock_.setDragging(false); this.fireMoveEvent_(); - this.draggedConnectionManager_.applyConnections(); - this.draggingBlock_.render(); + if (this.draggedConnectionManager_.wouldConnectBlock()) { + // Applying connections also rerenders the relevant blocks. + this.draggedConnectionManager_.applyConnections(); + } else { + this.draggingBlock_.render(); + } this.draggingBlock_.scheduleSnapAndBump(); } this.workspace_.setResizesEnabled(true); diff --git a/core/dragged_connection_manager.js b/core/dragged_connection_manager.js index fc5525fd5..2e75a3b47 100644 --- a/core/dragged_connection_manager.js +++ b/core/dragged_connection_manager.js @@ -125,6 +125,16 @@ Blockly.DraggedConnectionManager.prototype.wouldDeleteBlock = function() { return this.wouldDeleteBlock_; }; +/** + * Return whether the block would be deleted if dropped immediately, based on + * information from the most recent move event. + * @return {boolean} true if the block would be deleted if dropped immediately. + * @package + */ +Blockly.DraggedConnectionManager.prototype.wouldConnectBlock = function() { + return !!this.closestConnection_; +}; + /** * Connect to the closest connection and render the results. * This should be called at the end of a drag. diff --git a/core/events.js b/core/events.js index cb2827171..265f5114d 100644 --- a/core/events.js +++ b/core/events.js @@ -204,15 +204,22 @@ Blockly.Events.filter = function(queueIn, forward) { for (var i = 0, event; event = queue[i]; i++) { if (!event.isNull()) { var key = [event.type, event.blockId, event.workspaceId].join(' '); - var lastEvent = hash[key]; - if (!lastEvent) { - hash[key] = event; + + var lastEntry = hash[key]; + var lastEvent = lastEntry ? lastEntry.event : null; + if (!lastEntry) { + // Each item in the hash table has the event and the index of that event + // in the input array. This lets us make sure we only merge adjacent + // move events. + hash[key] = { event: event, index: i}; mergedQueue.push(event); - } else if (event.type == Blockly.Events.MOVE) { + } else if (event.type == Blockly.Events.MOVE && + lastEntry.index == i - 1) { // Merge move events. lastEvent.newParentId = event.newParentId; lastEvent.newInputName = event.newInputName; lastEvent.newCoordinate = event.newCoordinate; + lastEntry.index = i; } else if (event.type == Blockly.Events.CHANGE && event.element == lastEvent.element && event.name == lastEvent.name) { @@ -227,7 +234,7 @@ Blockly.Events.filter = function(queueIn, forward) { lastEvent.newValue = event.newValue; } else { // Collision: newer events should merge into this event to maintain order - hash[key] = event; + hash[key] = { event: event, index: 1}; mergedQueue.push(event); } } diff --git a/tests/jsunit/event_test.js b/tests/jsunit/event_test.js index 40020490a..9643a01bf 100644 --- a/tests/jsunit/event_test.js +++ b/tests/jsunit/event_test.js @@ -790,3 +790,30 @@ function test_events_newblock_newvar_xml() { Blockly.Events.fire = savedFireFunc; } } + +function test_events_filter_nomerge_move() { + // Move events should only merge if they refer to the same block and are + // consecutive. + eventTest_setUpWithMockBlocks(); + try { + var block1 = createSimpleTestBlock(workspace); + var block2 = createSimpleTestBlock(workspace); + + var events = []; + helper_addMoveEvent(events, block1, 1, 1); + helper_addMoveEvent(events, block2, 1, 1); + events.push(new Blockly.Events.BlockDelete(block2)); + helper_addMoveEvent(events, block1, 2, 2); + + var filteredEvents = Blockly.Events.filter(events, true); + // Nothing should have merged. + assertEquals(4, filteredEvents.length); + // test that the order hasn't changed + assertTrue(filteredEvents[0] instanceof Blockly.Events.BlockMove); + assertTrue(filteredEvents[1] instanceof Blockly.Events.BlockMove); + assertTrue(filteredEvents[2] instanceof Blockly.Events.BlockDelete); + assertTrue(filteredEvents[3] instanceof Blockly.Events.BlockMove); + } finally { + eventTest_tearDownWithMockBlocks(); + } +}