From 55784580e9657b7b65c5a050b6c8592828ad60c1 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Sun, 6 Mar 2016 18:32:20 -0800 Subject: [PATCH] Group mutations into same event. --- core/block_svg.js | 4 ++-- core/events.js | 25 +++++++++++++++++++++---- core/mutator.js | 31 +++++++++++++++++++------------ core/workspace.js | 16 ++++++++++------ 4 files changed, 52 insertions(+), 24 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index 387294286..12d47b61d 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -227,12 +227,12 @@ Blockly.BlockSvg.terminateDrag_ = function() { Blockly.Events.setGroup(group); selected.snapToGrid(); Blockly.Events.setGroup(false); - }, Blockly.BUMP_DELAY / 2) + }, Blockly.BUMP_DELAY / 2); setTimeout(function() { Blockly.Events.setGroup(group); selected.bumpNeighbours_(); Blockly.Events.setGroup(false); - }, Blockly.BUMP_DELAY) + }, Blockly.BUMP_DELAY); // Fire an event to allow scrollbars to resize. Blockly.fireUiEvent(window, 'resize'); } diff --git a/core/events.js b/core/events.js index ff7834c88..3f6cfb208 100644 --- a/core/events.js +++ b/core/events.js @@ -97,7 +97,7 @@ Blockly.Events.fire = function(event) { * @private */ Blockly.Events.fireNow_ = function() { - var queue = Blockly.Events.filter_(Blockly.Events.FIRE_QUEUE_); + var queue = Blockly.Events.filter(Blockly.Events.FIRE_QUEUE_); Blockly.Events.FIRE_QUEUE_.length = 0; for (var i = 0, event; event = queue[i]; i++) { var workspace = Blockly.Workspace.getById(event.workspaceId); @@ -111,9 +111,8 @@ Blockly.Events.fireNow_ = function() { * Filter the queued events and merge duplicates. * @param {!Array.} queueIn Array of events. * @return {!Array.} Array of filtered events. - * @private */ -Blockly.Events.filter_ = function(queueIn) { +Blockly.Events.filter = function(queueIn) { var queue = goog.array.clone(queueIn); // Merge duplicates. O(n^2), but n should be very small. for (var i = 0, event1; event1 = queue[i]; i++) { @@ -145,6 +144,14 @@ Blockly.Events.filter_ = function(queueIn) { queue.splice(i, 1); } } + // Move mutation events to the top of the queue. + // Intentionally skip first event. + for (var i = 1, event; event = queue[i]; i++) { + if (event.type == Blockly.Events.CHANGE && + event.element == 'mutation') { + queue.unshift(queue.splice(i, 1)[0]); + } + } return queue; }; @@ -335,6 +342,8 @@ Blockly.Events.Change.prototype.run = function(forward) { var field = block.getField(this.name); if (field) { field.setValue(value); + } else { + console.warn("Can't set non-existant field: " + this.name); } break; case 'comment': @@ -354,10 +363,17 @@ Blockly.Events.Change.prototype.run = function(forward) { // Close the mutator (if open) since we don't want to update it. block.mutator.setVisible(false); } + var oldMutation = ''; + if (block.mutationToDom) { + var oldMutationDom = block.mutationToDom(); + oldMutation = oldMutationDom && Blockly.Xml.domToText(oldMutationDom); + } if (block.domToMutation) { var dom = Blockly.Xml.textToDom('' + value + ''); block.domToMutation(dom.firstChild); } + Blockly.Events.fire(new Blockly.Events.Change( + block, 'mutation', null, oldMutation, value)); break; } }; @@ -457,6 +473,8 @@ Blockly.Events.Move.prototype.run = function(forward) { var input = parentBlock.getInput(inputName); if (input) { parentConnection = input.connection; + } else { + console.warn("Can't connect to non-existant input: " + inputName); } } else if (blockConnection.type == Blockly.PREVIOUS_STATEMENT) { parentConnection = parentBlock.nextConnection; @@ -466,4 +484,3 @@ Blockly.Events.Move.prototype.run = function(forward) { } } }; - diff --git a/core/mutator.js b/core/mutator.js index 31c81512f..b3e9d90e8 100644 --- a/core/mutator.js +++ b/core/mutator.js @@ -280,29 +280,36 @@ Blockly.Mutator.prototype.workspaceChanged_ = function() { // When the mutator's workspace changes, update the source block. if (this.rootBlock_.workspace == this.workspace_) { - var oldMutationDom = this.block_.mutationToDom(); + Blockly.Events.setGroup(true); + var block = this.block_; + var oldMutationDom = block.mutationToDom(); var oldMutation = oldMutationDom && Blockly.Xml.domToText(oldMutationDom); // Switch off rendering while the source block is rebuilt. - var savedRendered = this.block_.rendered; - this.block_.rendered = false; + var savedRendered = block.rendered; + block.rendered = false; // Allow the source block to rebuild itself. - this.block_.compose(this.rootBlock_); + block.compose(this.rootBlock_); // Restore rendering and show the changes. - this.block_.rendered = savedRendered; + block.rendered = savedRendered; // Mutation may have added some elements that need initalizing. - this.block_.initSvg(); - var newMutationDom = this.block_.mutationToDom(); + block.initSvg(); + var newMutationDom = block.mutationToDom(); var newMutation = newMutationDom && Blockly.Xml.domToText(newMutationDom); if (oldMutation != newMutation) { Blockly.Events.fire(new Blockly.Events.Change( - this.block_, 'mutation', null, oldMutation, newMutation)); - goog.Timer.callOnce( - this.block_.bumpNeighbours_, Blockly.BUMP_DELAY, this.block_); + block, 'mutation', null, oldMutation, newMutation)); + // Ensure that any bump is part of this mutation's event group. + var group = Blockly.Events.getGroup(); + setTimeout(function() { + Blockly.Events.setGroup(group); + block.bumpNeighbours_(); + }, Blockly.BUMP_DELAY); } - if (this.block_.rendered) { - this.block_.render(); + if (block.rendered) { + block.render(); } this.resizeBubble_(); + Blockly.Events.setGroup(false); } }; diff --git a/core/workspace.js b/core/workspace.js index b2a951ac4..49f3fac88 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -214,15 +214,19 @@ Blockly.Workspace.prototype.undo = function(redo) { if (!event) { return; } - Blockly.Events.recordUndo = false; - event.run(redo); - Blockly.Events.recordUndo = true; - (redo ? this.undoStack_ : this.redoStack_).push(event); + var events = [event]; // Do another undo/redo if the next one is of the same group. - if (sourceStack.length && event.group && + while (sourceStack.length && event.group && event.group == sourceStack[sourceStack.length - 1].group) { - this.undo(redo); + events.push(sourceStack.pop()); } + events = Blockly.Events.filter(events); + Blockly.Events.recordUndo = false; + for (var i = 0, event; event = events[i]; i++) { + event.run(redo); + (redo ? this.undoStack_ : this.redoStack_).push(event); + } + Blockly.Events.recordUndo = true; }; /**