factor out getX and getY methods for flyouts (#4463)

This commit is contained in:
Maribeth Bottorff
2020-11-19 10:12:06 -08:00
committed by GitHub
parent 7fce707161
commit b5c77137bd
4 changed files with 301 additions and 60 deletions

View File

@@ -118,6 +118,62 @@ Blockly.HorizontalFlyout.prototype.setMetrics_ = function(xyRatio) {
this.workspace_.scrollY + metrics.absoluteTop);
};
/**
* Calculates the x coordinate for the flyout position.
* @return {number} X coordinate.
*/
Blockly.HorizontalFlyout.prototype.getX = function() {
// X is always 0 since this is a horizontal flyout.
return 0;
};
/**
* Calculates the y coordinate for the flyout position.
* @return {number} Y coordinate.
*/
Blockly.HorizontalFlyout.prototype.getY = function() {
var targetWorkspaceMetrics = this.targetWorkspace.getMetrics();
if (!targetWorkspaceMetrics) {
// Hidden components will return null.
return 0;
}
var y = 0;
// If this flyout is not the trashcan flyout (e.g. toolbox or mutator).
if (this.targetWorkspace.toolboxPosition == this.toolboxPosition_) {
// If there is a category toolbox.
if (targetWorkspaceMetrics.toolboxHeight) {
if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_TOP) {
y = targetWorkspaceMetrics.toolboxHeight;
} else {
y = targetWorkspaceMetrics.viewHeight - this.height_;
}
// Simple (flyout-only) toolbox.
} else {
if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_TOP) {
y = 0;
} else {
// The simple flyout does not cover the workspace.
y = targetWorkspaceMetrics.viewHeight;
}
}
// Trashcan flyout is opposite the main flyout.
} else {
if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_TOP) {
y = 0;
} else {
// Because the anchor point of the flyout is on the top, but we want
// to align the bottom edge of the flyout with the bottom edge of the
// blocklyDiv, we calculate the full height of the div minus the height
// of the flyout.
y = targetWorkspaceMetrics.viewHeight +
targetWorkspaceMetrics.absoluteTop - this.height_;
}
}
return y;
};
/**
* Move the flyout to the edge of the workspace.
*/
@@ -137,36 +193,9 @@ Blockly.HorizontalFlyout.prototype.position = function() {
var edgeHeight = this.height_ - this.CORNER_RADIUS;
this.setBackgroundPath_(edgeWidth, edgeHeight);
// X is always 0 since this is a horizontal flyout.
var x = 0;
// If this flyout is the toolbox flyout.
if (this.targetWorkspace.toolboxPosition == this.toolboxPosition_) {
// If there is a toolbox.
if (targetWorkspaceMetrics.toolboxHeight) {
if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_TOP) {
var y = targetWorkspaceMetrics.toolboxHeight;
} else {
var y = targetWorkspaceMetrics.viewHeight - this.height_;
}
} else {
if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_TOP) {
var y = 0;
} else {
var y = targetWorkspaceMetrics.viewHeight;
}
}
} else {
if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_TOP) {
var y = 0;
} else {
// Because the anchor point of the flyout is on the top, but we want
// to align the bottom edge of the flyout with the bottom edge of the
// blocklyDiv, we calculate the full height of the div minus the height
// of the flyout.
var y = targetWorkspaceMetrics.viewHeight +
targetWorkspaceMetrics.absoluteTop - this.height_;
}
}
var x = this.getX();
var y = this.getY();
this.positionAt_(this.width_, this.height_, x, y);
};

View File

@@ -121,6 +121,63 @@ Blockly.VerticalFlyout.prototype.setMetrics_ = function(xyRatio) {
this.workspace_.scrollY + metrics.absoluteTop);
};
/**
* Calculates the x coordinate for the flyout position.
* @return {number} X coordinate.
*/
Blockly.VerticalFlyout.prototype.getX = function() {
var targetWorkspaceMetrics = this.targetWorkspace.getMetrics();
if (!targetWorkspaceMetrics) {
// Hidden components will return null.
return 0;
}
var x = 0;
// If this flyout is not the trashcan flyout (e.g. toolbox or mutator).
if (this.targetWorkspace.toolboxPosition == this.toolboxPosition_) {
// If there is a category toolbox.
if (targetWorkspaceMetrics.toolboxWidth) {
if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_LEFT) {
x = targetWorkspaceMetrics.toolboxWidth;
} else {
x = targetWorkspaceMetrics.viewWidth - this.width_;
}
// Simple (flyout-only) toolbox.
} else {
if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_LEFT) {
x = 0;
} else {
// The simple flyout does not cover the workspace.
x = targetWorkspaceMetrics.viewWidth;
}
}
// Trashcan flyout is opposite the main flyout.
} else {
if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_LEFT) {
x = 0;
} else {
// Because the anchor point of the flyout is on the left, but we want
// to align the right edge of the flyout with the right edge of the
// blocklyDiv, we calculate the full width of the div minus the width
// of the flyout.
x = targetWorkspaceMetrics.viewWidth +
targetWorkspaceMetrics.absoluteLeft - this.width_;
}
}
return x;
};
/**
* Calculates the y coordinate for the flyout position.
* @return {number} Y coordinate.
*/
Blockly.VerticalFlyout.prototype.getY = function() {
// Y is always 0 since this is a vertical flyout.
return 0;
};
/**
* Move the flyout to the edge of the workspace.
*/
@@ -140,36 +197,9 @@ Blockly.VerticalFlyout.prototype.position = function() {
var edgeHeight = targetWorkspaceMetrics.viewHeight - 2 * this.CORNER_RADIUS;
this.setBackgroundPath_(edgeWidth, edgeHeight);
// Y is always 0 since this is a vertical flyout.
var y = 0;
// If this flyout is the toolbox flyout.
if (this.targetWorkspace.toolboxPosition == this.toolboxPosition_) {
// If there is a category toolbox.
if (targetWorkspaceMetrics.toolboxWidth) {
if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_LEFT) {
var x = targetWorkspaceMetrics.toolboxWidth;
} else {
var x = targetWorkspaceMetrics.viewWidth - this.width_;
}
} else {
if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_LEFT) {
var x = 0;
} else {
var x = targetWorkspaceMetrics.viewWidth;
}
}
} else {
if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_LEFT) {
var x = 0;
} else {
// Because the anchor point of the flyout is on the left, but we want
// to align the right edge of the flyout with the right edge of the
// blocklyDiv, we calculate the full width of the div minus the width
// of the flyout.
var x = targetWorkspaceMetrics.viewWidth +
targetWorkspaceMetrics.absoluteLeft - this.width_;
}
}
var x = this.getX();
var y = this.getY();
this.positionAt_(this.width_, this.height_, x, y);
};

View File

@@ -161,6 +161,18 @@ Blockly.IFlyout.prototype.reflow;
*/
Blockly.IFlyout.prototype.isScrollable;
/**
* Calculates the x coordinate for the flyout position.
* @return {number} X coordinate.
*/
Blockly.IFlyout.prototype.getX;
/**
* Calculates the y coordinate for the flyout position.
* @return {number} Y coordinate.
*/
Blockly.IFlyout.prototype.getY;
/**
* Position the flyout.
* @return {void}

View File

@@ -29,6 +29,176 @@ suite('Flyout', function() {
sharedTestTeardown.call(this);
});
suite('position', function() {
suite('vertical flyout', function() {
suite('simple flyout', function() {
setup(function() {
this.flyout = this.workspace.getFlyout();
});
test('y is always 0', function() {
chai.assert.equal(this.flyout.getY(), 0, 'y coordinate in vertical flyout should be 0');
});
test('x is right of workspace if flyout at right', function() {
sinon.stub(this.flyout.targetWorkspace, 'getMetrics').returns({
viewWidth: 100,
});
this.flyout.targetWorkspace.toolboxPosition = Blockly.TOOLBOX_AT_RIGHT;
this.flyout.toolboxPosition_ = Blockly.TOOLBOX_AT_RIGHT;
chai.assert.equal(this.flyout.getX(), 100, 'x should be right of workspace');
});
test('x is 0 if flyout at left', function() {
this.flyout.targetWorkspace.toolboxPosition = Blockly.TOOLBOX_AT_LEFT;
this.flyout.toolboxPosition_ = Blockly.TOOLBOX_AT_LEFT;
chai.assert.equal(this.flyout.getX(), 0, 'x should be 0 if the flyout is on the left');
});
});
suite('toolbox flyout', function() {
setup(function() {
var toolbox = document.getElementById('toolbox-categories');
this.workspace = Blockly.inject('blocklyDiv',
{
toolbox: toolbox
});
this.flyout = this.workspace.getToolbox().getFlyout();
});
teardown(function() {
workspaceTeardown.call(this, this.workspace);
});
test('x is aligned with toolbox at left', function() {
sinon.stub(this.flyout.targetWorkspace, 'getMetrics').returns({
toolboxWidth: 20,
});
this.flyout.targetWorkspace.toolboxPosition = Blockly.TOOLBOX_AT_LEFT;
this.flyout.toolboxPosition_ = Blockly.TOOLBOX_AT_LEFT;
chai.assert.equal(this.flyout.getX(), 20, 'x should be aligned with toolbox');
});
test('x is aligned with toolbox at right', function() {
sinon.stub(this.flyout.targetWorkspace, 'getMetrics').returns({
toolboxWidth: 20,
viewWidth: 100,
});
this.flyout.width_ = 10;
this.flyout.targetWorkspace.toolboxPosition = Blockly.TOOLBOX_AT_RIGHT;
this.flyout.toolboxPosition_ = Blockly.TOOLBOX_AT_RIGHT;
chai.assert.equal(this.flyout.getX(), 90,'x + width should be aligned with toolbox');
});
});
// These tests simulate a trashcan flyout, i.e. the flyout under test is on the
// opposite side of the workspace toolbox setting.
suite('trashcan flyout', function() {
setup(function() {
this.flyout = this.workspace.getFlyout();
});
test('x is 0 if trashcan on left', function() {
sinon.stub(this.flyout.targetWorkspace, 'getMetrics').returns({
viewWidth: 100,
});
this.flyout.targetWorkspace.toolboxPosition = Blockly.TOOLBOX_AT_RIGHT;
this.flyout.toolboxPosition_ = Blockly.TOOLBOX_AT_LEFT;
chai.assert.equal(this.flyout.getX(), 0, 'x should be aligned with left edge');
});
test('trashcan on right covers right edge of workspace', function() {
this.flyout.width_ = 20;
sinon.stub(this.flyout.targetWorkspace, 'getMetrics').returns({
viewWidth: 100,
absoluteLeft: 10,
});
this.flyout.targetWorkspace.toolboxPosition = Blockly.TOOLBOX_AT_LEFT;
this.flyout.toolboxPosition_ = Blockly.TOOLBOX_AT_RIGHT;
chai.assert.equal(this.flyout.getX(), 90, 'x + width should be aligned with right edge');
});
});
});
suite('horizontal flyout', function() {
setup(function() {
this.workspace = Blockly.inject('blocklyDiv',
{
toolbox: this.toolboxXml,
horizontalLayout: true,
});
});
teardown(function() {
workspaceTeardown.call(this, this.workspace);
});
suite('simple flyout', function() {
setup(function() {
this.flyout = this.workspace.getFlyout();
});
test('x is always 0', function() {
chai.assert.equal(this.flyout.getX(), 0, 'x coordinate in horizontal flyout should be 0');
});
test('y is 0 if flyout at top', function() {
this.flyout.targetWorkspace.toolboxPosition = Blockly.TOOLBOX_AT_TOP;
this.flyout.toolboxPosition_ = Blockly.TOOLBOX_AT_TOP;
chai.assert.equal(this.flyout.getY(), 0, 'y should be 0 if flyout is at the top');
});
test('y is below workspace if flyout at bottom', function() {
this.flyout.targetWorkspace.toolboxPosition = Blockly.TOOLBOX_AT_BOTTOM;
this.flyout.toolboxPosition_ = Blockly.TOOLBOX_AT_BOTTOM;
sinon.stub(this.flyout.targetWorkspace, 'getMetrics').returns({
viewHeight: 50,
});
chai.assert.equal(this.flyout.getY(), 50, 'y should be below the workspace');
});
});
suite('toolbox flyout', function() {
setup(function() {
var toolbox = document.getElementById('toolbox-categories');
this.workspace = Blockly.inject('blocklyDiv',
{
toolbox: toolbox,
horizontalLayout: true,
});
this.flyout = this.workspace.getToolbox().getFlyout();
});
teardown(function() {
workspaceTeardown.call(this, this.workspace);
});
test('y is aligned with toolbox at top', function() {
sinon.stub(this.flyout.targetWorkspace, 'getMetrics').returns({
toolboxHeight: 20,
});
this.flyout.targetWorkspace.toolboxPosition = Blockly.TOOLBOX_AT_TOP;
this.flyout.toolboxPosition_ = Blockly.TOOLBOX_AT_TOP;
chai.assert.equal(this.flyout.getY(), 20, 'y should be aligned with toolbox');
});
test('y is aligned with toolbox at bottom', function() {
sinon.stub(this.flyout.targetWorkspace, 'getMetrics').returns({
toolboxHeight: 20,
viewHeight: 100,
});
this.flyout.height_ = 30;
this.flyout.targetWorkspace.toolboxPosition = Blockly.TOOLBOX_AT_BOTTOM;
this.flyout.toolboxPosition_ = Blockly.TOOLBOX_AT_BOTTOM;
chai.assert.equal(this.flyout.getY(), 70, 'y + height should be aligned with toolbox');
});
});
// These tests simulate a trashcan flyout, i.e. the flyout under test is on the
// opposite side of the workspace toolbox setting.
suite('trashcan flyout', function() {
setup(function() {
this.flyout = this.workspace.getFlyout();
});
test('y is 0 if trashcan at top', function() {
this.flyout.targetWorkspace.toolboxPosition = Blockly.TOOLBOX_AT_BOTTOM;
this.flyout.toolboxPosition_ = Blockly.TOOLBOX_AT_TOP;
chai.assert.equal(this.flyout.getY(), 0, 'y should be aligned with top');
});
test('trashcan on bottom covers bottom of workspace', function() {
this.flyout.targetWorkspace.toolboxPosition = Blockly.TOOLBOX_AT_TOP;
this.flyout.toolboxPosition_ = Blockly.TOOLBOX_AT_BOTTOM;
sinon.stub(this.flyout.targetWorkspace, 'getMetrics').returns({
viewHeight: 50,
absoluteTop: 10,
});
this.flyout.height_ = 20;
chai.assert.equal(this.flyout.getY(), 40, 'y + height should be aligned with bottom');
});
});
});
});
suite('createFlyoutInfo_', function() {
setup(function() {
this.simpleToolboxJSON = getSimpleJSON();