Viewport change event (#4180)

* Adding viewport ui event emitting and tests

* comment out viewport ui event logic and add TODO for reference
This commit is contained in:
Monica Kozbial
2020-08-31 18:41:20 -07:00
committed by GitHub
parent 61bdbc5034
commit 739b8b3adc
3 changed files with 276 additions and 7 deletions

View File

@@ -107,11 +107,19 @@ Blockly.ScrollbarPair.prototype.resize = function() {
resizeV = true;
}
}
if (resizeH) {
this.hScroll.resize(hostMetrics);
}
if (resizeV) {
this.vScroll.resize(hostMetrics);
if (resizeH || resizeV) {
try {
Blockly.Events.disable();
if (resizeH) {
this.hScroll.resize(hostMetrics);
}
if (resizeV) {
this.vScroll.resize(hostMetrics);
}
} finally {
Blockly.Events.enable();
}
this.workspace_.maybeFireViewportChangeEvent();
}
// Reposition the corner square.

View File

@@ -323,6 +323,28 @@ Blockly.WorkspaceSvg.prototype.dragDeltaXY_ = null;
*/
Blockly.WorkspaceSvg.prototype.scale = 1;
// TODO(#4203) Enable viewport events after ui events refactor.
// /**
// * Cached scale value. Used to detect changes in viewport.
// * @type {number}
// * @private
// */
// Blockly.WorkspaceSvg.prototype.oldScale_ = 1;
//
// /**
// * Cached viewport top value. Used to detect changes in viewport.
// * @type {number}
// * @private
// */
// Blockly.WorkspaceSvg.prototype.oldTop_ = 0;
//
// /**
// * Cached viewport left value. Used to detect changes in viewport.
// * @type {number}
// * @private
// */
// Blockly.WorkspaceSvg.prototype.oldLeft_ = 0;
/**
* The workspace's trashcan (if any).
* @type {Blockly.Trashcan}
@@ -1073,6 +1095,31 @@ Blockly.WorkspaceSvg.prototype.getParentSvg = function() {
return /** @type {!SVGElement} */ (this.cachedParentSvg_);
};
/**
* Fires a viewport event if events are enabled and there is a change in
* viewport values.
* @package
*/
Blockly.WorkspaceSvg.prototype.maybeFireViewportChangeEvent = function() {
// TODO(#4203) Enable viewport events after ui events refactor.
// if (!Blockly.Events.isEnabled()) {
// return;
// }
// var scale = this.scale;
// var top = -this.scrollY;
// var left = -this.scrollX;
// if (scale == this.oldScale_ && top == this.oldTop_ && left == this.oldLeft_) {
// return;
// }
// this.oldScale_ = scale;
// this.oldTop_ = top;
// this.oldLeft_ = left;
// var event = new Blockly.Events.Ui(null, 'viewport', null,
// { scale: scale, top: top, left: left });
// event.workspaceId = this.id;
// Blockly.Events.fire(event);
};
/**
* Translate this workspace to new coordinates.
* @param {number} x Horizontal translation, in pixel units relative to the
@@ -1097,6 +1144,8 @@ Blockly.WorkspaceSvg.prototype.translate = function(x, y) {
if (this.grid_) {
this.grid_.moveTo(x, y);
}
this.maybeFireViewportChangeEvent();
};
/**
@@ -1891,8 +1940,14 @@ Blockly.WorkspaceSvg.prototype.zoomToFit = function() {
// Scale Units: (pixels / workspaceUnit)
var ratioX = workspaceWidth / blocksWidth;
var ratioY = workspaceHeight / blocksHeight;
this.setScale(Math.min(ratioX, ratioY));
this.scrollCenter();
Blockly.Events.disable();
try {
this.setScale(Math.min(ratioX, ratioY));
this.scrollCenter();
} finally {
Blockly.Events.enable();
}
this.maybeFireViewportChangeEvent();
};
/**

View File

@@ -164,6 +164,212 @@ suite('WorkspaceSvg', function() {
});
});
suite.skip('Viewport change events', function() {
function resetEventHistory(eventsFireStub, changeListenerSpy) {
eventsFireStub.resetHistory();
changeListenerSpy.resetHistory();
}
function assertSpyFiredViewportEvent(spy, workspace, expectedProperties) {
assertEventFired(
spy, Blockly.Events.Ui, {element: 'viewport'},
workspace.id, null);
assertEventFired(spy, Blockly.Events.Ui, expectedProperties,
workspace.id, null);
}
function assertViewportEventFired(eventsFireStub, changeListenerSpy,
workspace, expectedEventCount = 1) {
var metrics = workspace.getMetrics();
var expectedProperties = {
element: 'viewport',
newValue: {scale: workspace.scale, top: metrics.viewTop,
left: metrics.viewLeft}
};
assertSpyFiredViewportEvent(
eventsFireStub, workspace, expectedProperties);
assertSpyFiredViewportEvent(
changeListenerSpy, workspace,expectedProperties);
sinon.assert.callCount(changeListenerSpy, expectedEventCount);
sinon.assert.callCount(eventsFireStub, expectedEventCount);
}
function runViewportEventTest(eventTriggerFunc, eventsFireStub,
changeListenerSpy, workspace, clock, expectedEventCount = 1) {
clock.runAll();
resetEventHistory(eventsFireStub, changeListenerSpy);
eventTriggerFunc();
assertViewportEventFired(
eventsFireStub, changeListenerSpy, workspace, expectedEventCount);
}
setup(function() {
defineStackBlock();
this.changeListenerSpy = createFireChangeListenerSpy(this.workspace);
});
teardown(function() {
delete Blockly.Blocks['stack_block'];
});
suite('zoom', function() {
test('setScale', function() {
runViewportEventTest(() => this.workspace.setScale(2),
this.eventsFireStub, this.changeListenerSpy, this.workspace,
this.clock);
});
test('zoom(50, 50, 1)', function() {
runViewportEventTest(() => this.workspace.zoom(50, 50, 1),
this.eventsFireStub, this.changeListenerSpy, this.workspace,
this.clock);
});
test('zoom(50, 50, -1)', function() {
runViewportEventTest(() => this.workspace.zoom(50, 50, -1),
this.eventsFireStub, this.changeListenerSpy, this.workspace,
this.clock);
});
test('zoomCenter(1)', function() {
runViewportEventTest(() => this.workspace.zoomCenter(1),
this.eventsFireStub, this.changeListenerSpy, this.workspace,
this.clock);
});
test('zoomCenter(-1)', function() {
runViewportEventTest(() => this.workspace.zoomCenter(-1),
this.eventsFireStub, this.changeListenerSpy, this.workspace,
this.clock);
});
test('zoomToFit', function() {
var block = this.workspace.newBlock('stack_block');
block.initSvg();
block.render();
runViewportEventTest(() => this.workspace.zoomToFit(),
this.eventsFireStub, this.changeListenerSpy, this.workspace,
this.clock);
});
});
suite('scroll', function() {
test('centerOnBlock', function() {
var block = this.workspace.newBlock('stack_block');
block.initSvg();
block.render();
runViewportEventTest(() => this.workspace.zoomToFit(block.id),
this.eventsFireStub, this.changeListenerSpy, this.workspace,
this.clock);
});
test('scroll', function() {
runViewportEventTest(() => this.workspace.scroll(50, 50),
this.eventsFireStub, this.changeListenerSpy, this.workspace,
this.clock);
});
test('scrollCenter', function() {
runViewportEventTest(() => this.workspace.scrollCenter(),
this.eventsFireStub, this.changeListenerSpy, this.workspace,
this.clock);
});
});
suite('resize', function() {
setup(function() {
sinon.stub(Blockly, 'svgSize').callsFake((svg) => {
return new Blockly.utils.Size(
svg.cachedWidth_ + 10, svg.cachedHeight_ + 10);
});
});
test('resize', function() {
runViewportEventTest(() => this.workspace.resize(),
this.eventsFireStub, this.changeListenerSpy, this.workspace,
this.clock);
});
test('resizeContents', function() {
runViewportEventTest(() => this.workspace.resizeContents(),
this.eventsFireStub, this.changeListenerSpy, this.workspace,
this.clock);
});
});
suite('Blocks triggering viewport changes', function() {
test('block render that doesn\'t trigger scroll', function() {
this.clock.runAll();
resetEventHistory(this.eventsFireStub, this.changeListenerSpy);
var block = this.workspace.newBlock('stack_block');
block.initSvg();
block.render();
this.clock.runAll();
assertEventNotFired(
this.eventsFireStub, Blockly.Events.Ui, {element: 'viewport'});
});
test('block move that triggers scroll', function() {
var block = this.workspace.newBlock('stack_block');
block.initSvg();
block.render();
this.clock.runAll();
resetEventHistory(this.eventsFireStub, this.changeListenerSpy);
// Expect 2 events, 1 move, 1 viewport
runViewportEventTest(() => {
block.moveBy(1000, 1000);
}, this.eventsFireStub, this.changeListenerSpy, this.workspace,
this.clock, 2);
});
test.skip('domToWorkspace that doesn\'t trigger scroll' , function() {
// TODO(#4192): un-skip after fixing bug with unintentional scroll.
// 4 blocks with space in center.
Blockly.Xml.domToWorkspace(
Blockly.Xml.textToDom(
'<xml xmlns="https://developers.google.com/blockly/xml">' +
'<block type="controls_if" x="88" y="88"></block>' +
'<block type="controls_if" x="288" y="88"></block>' +
'<block type="controls_if" x="88" y="238"></block>' +
'<block type="controls_if" x="288" y="238"></block>' +
'</xml>'),
this.workspace);
var xmlDom = Blockly.Xml.textToDom(
'<block type="controls_if" x="188" y="163"></block>');
this.clock.runAll();
resetEventHistory(this.eventsFireStub, this.changeListenerSpy);
// Add block in center of other blocks, not triggering scroll.
Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom(
'<block type="controls_if" x="188" y="163"></block>'), this.workspace);
this.clock.runAll();
assertEventNotFired(
this.eventsFireStub, Blockly.Events.Ui, {element: 'viewport'});
assertEventNotFired(
this.changeListenerSpy, Blockly.Events.Ui, {element: 'viewport'});
});
test('domToWorkspace at 0,0 that doesn\'t trigger scroll' , function() {
// 4 blocks with space in center.
Blockly.Xml.domToWorkspace(
Blockly.Xml.textToDom(
'<xml xmlns="https://developers.google.com/blockly/xml">' +
'<block type="controls_if" x="-75" y="-72"></block>' +
'<block type="controls_if" x="75" y="-72"></block>' +
'<block type="controls_if" x="-75" y="75"></block>' +
'<block type="controls_if" x="75" y="75"></block>' +
'</xml>'),
this.workspace);
var xmlDom = Blockly.Xml.textToDom(
'<block type="controls_if" x="0" y="0"></block>');
this.clock.runAll();
resetEventHistory(this.eventsFireStub, this.changeListenerSpy);
// Add block in center of other blocks, not triggering scroll.
Blockly.Xml.domToWorkspace(xmlDom, this.workspace);
this.clock.runAll();
assertEventNotFired(
this.eventsFireStub, Blockly.Events.Ui, {element: 'viewport'});
assertEventNotFired(
this.changeListenerSpy, Blockly.Events.Ui, {element: 'viewport'});
});
test('domToWorkspace multiple blocks triggers one viewport event', function() {
var addingMultipleBlocks = () => {
Blockly.Xml.domToWorkspace(
Blockly.Xml.textToDom(
'<xml xmlns="https://developers.google.com/blockly/xml">' +
'<block type="controls_if" x="88" y="88"></block>' +
'<block type="controls_if" x="288" y="88"></block>' +
'<block type="controls_if" x="88" y="238"></block>' +
'<block type="controls_if" x="288" y="238"></block>' +
'</xml>'),
this.workspace);
};
// Expect 10 events, 4 create, 4 move, 1 viewport, 1 finished loading
runViewportEventTest(addingMultipleBlocks, this.eventsFireStub,
this.changeListenerSpy, this.workspace, this.clock, 10);
});
});
});
suite('Workspace Base class', function() {
testAWorkspace();
});